React 是一个广泛使用的前端开发框架,它的虚拟 DOM 和单向数据流模型为开发者提供了高效的开发体验。Redux 是一个可预测的状态容器,它帮助我们管理着应用程序的状态。React-Router 则是处理页面路由的库,它可以帮助我们组织我们的 React 应用程序,并让我们实现更好的用户导航体验。
本篇文章主要介绍一种使用 React、Redux 和 React-Router 搭建前端网站的技术方案,并提供完整的实例代码,以供读者学习和参考。
前置知识
在学习本文的内容之前,你需要掌握以下技术:
- 基础的 HTML、CSS 和 JavaScript 知识
- 熟悉 React 的组件化开发模式
- 了解 Redux 的基本使用方法
- 掌握 React-Router 动态路由的使用
技术方案
本文使用的技术方案是采用 React 作为开发框架,Redux 作为状态容器,React-Router 用于处理前端路由,同时在开发过程中使用 Webpack 进行打包和部署。
目录结构
我们在开始编写代码之前需要构建项目目录结构。一个标准的 React + Redux + React-Router 目录结构如下:
// www.javascriptcn.com code example src/ ├── components │ ├── App.js │ └── ... ├── pages │ ├── About │ │ ├── About.js │ │ ├── about.scss │ │ └── ... │ └── ... ├── store │ ├── actions │ │ └── ... │ ├── reducers │ │ └── ... │ └── store.js ├── styles │ ├── global.scss │ └── ... └── index.js
components/文件夹中存放的是 React 组件。pages/文件夹中存放的是所有的页面,每一个页面都是一个 React 组件。store/文件夹中存放着 Redux 中的actions和reducers,以及 Redux 的store。styles/文件夹中存放的是所有的 CSS 和 SCSS 样式文件。index.js是应用程序的入口文件。
整合 React 和 React-Router
在 index.js 文件中,我们需要整合 React 和 React-Router:
// www.javascriptcn.com code example
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import App from './components/App';
import About from './pages/About/About';
ReactDOM.render(
<Router>
<Route path="/" component={App} />
<Route path="/about" component={About} />
</Router>,
document.getElementById('root')
);在上面的代码中,我们首先引入了 React、ReactDOM 和 React-Router 的相关模块,然后定义了两个路由:"/" 和 "/about"。这两个路由分别映射到 App 和 About 组件,并在 ReactDOM.render() 中渲染整个应用程序。
整合 Redux
现在,我们接着添加 Redux 功能。首先,我们需要在项目中引入 Redux 和 React-Redux 相关模块:
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './store/reducers/rootReducer';然后,我们创建一个 Redux store,使用 Provider 将 store 传递给我们的应用程序:
// www.javascriptcn.com code example
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<Router>
<Route path="/" component={App} />
<Route path="/about" component={About} />
</Router>
</Provider>,
document.getElementById('root')
);现在,我们可以在我们的组件中使用 Redux 中的数据了。例如,在 About 组件中,我们可以通过 react-redux 提供的 connect() 方法连接 Redux store:
import { connect } from 'react-redux';
class About extends React.Component {
// ...
}
export default connect(mapStateToProps)(About);样式
在本例中,我们使用 SCSS 来管理样式,使用 style-loader 和 css-loader 从 JavaScript 中加载 CSS。我们需要在 webpack.config.js 文件中如下配置:
// www.javascriptcn.com code example
module.exports = {
// ...
module: {
rules: [
{
test: /\.scss$/,
use: [
'style-loader', // creates style nodes from JS strings
'css-loader', // translates CSS into CommonJS
'sass-loader' // compiles Sass to CSS, using Node Sass by default
]
}
]
}
};示例代码
下面是一个完整的实例代码,实现了一个简单的计数器应用程序,可以使用 redux 控制器来加减数值。具体使用流程如下:
$ git clone git://github.com/joyeecheung/redux-counter.git $ cd redux-counter $ npm install $ npm start
效果如下图:
index.js
// www.javascriptcn.com code example
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import App from './components/App';
import About from './pages/About/About';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from './store/reducers/rootReducer';
const store = createStore(
rootReducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
ReactDOM.render(
<Provider store={store}>
<Router>
<Route path="/" component={App} />
<Route path="/about" component={About} />
</Router>
</Provider>,
document.getElementById('root')
);components/App.js
// www.javascriptcn.com code example
import React from 'react';
import './App.scss';
import { connect } from 'react-redux';
import { incrementCounter, decrementCounter } from '../store/actions/counterActions';
class App extends React.Component {
handleIncrement = () => {
this.props.incrementCounter();
};
handleDecrement = () => {
this.props.decrementCounter();
};
render() {
const { counter } = this.props;
return (
<div className="App">
<p className="App-intro">当前数值: {counter}</p>
<div className="buttons">
<button onClick={this.handleDecrement}>-</button>
<button onClick={this.handleIncrement}>+</button>
</div>
</div>
);
}
}
const mapStateToProps = state => {
return {
counter: state.counter
};
};
const mapDispatchToProps = dispatch => {
return {
incrementCounter: () => dispatch(incrementCounter()),
decrementCounter: () => dispatch(decrementCounter())
};
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(App);store/actions/counterActions.js
// www.javascriptcn.com code example
export const incrementCounter = () => {
return {
type: 'INCREMENT_COUNTER'
};
};
export const decrementCounter = () => {
return {
type: 'DECREMENT_COUNTER'
};
};store/reducers/counterReducer.js
// www.javascriptcn.com code example
const initState = 0;
const counterReducer = (state = initState, action) => {
switch (action.type) {
case 'INCREMENT_COUNTER':
return state + 1;
case 'DECREMENT_COUNTER':
return state - 1;
default:
return state;
}
};
export default counterReducer;store/reducers/rootReducer.js
import { combineReducers } from 'redux';
import counterReducer from './counterReducer';
const rootReducer = combineReducers({
counter: counterReducer
});
export default rootReducer;pages/About/About.js
// www.javascriptcn.com code example
import React from 'react';
import './about.scss';
class About extends React.Component {
render() {
return <div className="about-page">这里是 about 页面</div>;
}
}
export default About;styles/global.scss
// www.javascriptcn.com code example
@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700');
@import url('https://fonts.googleapis.com/icon?family=Material+Icons');
body {
font-family: 'Roboto', sans-serif;
background: #eee;
padding: 0;
margin: 0;
}pages/About/about.scss
.about-page {
background-color: #fff;
padding: 20px;
}总结
在本文中,我们介绍了如何使用 React、Redux 和 React-Router 搭建前端网站,并提供了完整的实例代码。希望读者可以通过学习本文的内容,掌握相关技术并在实际项目中应用。如果在其中遇到问题,可以随时进行查阅 React、Redux 和 React-Router 的相关文档。
Source: FunTeaLearn,Please indicate the source for reprints https://funteas.com/post/65a73f6badd4f0e0ff0390d8