1、一个demo,纯react实现 <--返回目录
效果:
项目结构:
index.js
import React from 'react' import ReactDOM from 'react-dom' import App from './components/app.jsx' ReactDOM.render(<App></App>, document.getElementById('app'))
app.jsx
import React from 'react' export default class App extends React.Component { constructor(props) { super(props) this.state = { count: 0 } } render() { return ( <div> <p>click {this.state.count} times</p> <select ref={select => this.select = select}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> </div> ) } increment = () => { const num = this.select.value * 1 const { count } = this.state this.setState({ count: count + num }) } decrement = () => { const num = this.select.value * 1 const { count } = this.state this.setState({ count: count - num }) } }
2、引入redux的实现 <--返回目录
下载依赖
npm install --save redux
redux工作流程
redux核心API
使用redux改造后,项目结构:
index.js
import React from 'react' import ReactDOM from 'react-dom' import { createStore } from 'redux' import App from './components/app.jsx' import { counter } from './redux/reducers.js' // 根据counter函数创建store对象 const store = createStore(counter) // 定义渲染根组件标签的函数 const render = () => { ReactDOM.render( <App store={store} />, document.getElementById('root') ) } // 初始化渲染 render() // 注册(订阅)监听, 一旦状态发生改变, 自动重新渲染 store.subscribe(render)
app.jsx
import React from 'react' import PropTypes from 'prop-types' import * as actions from '../redux/actions.js' export default class App extends React.Component { static propTypes = { store: PropTypes.object.isRequired, } render() { return ( <div> <p>click {this.props.store.getState()} times</p> <select ref={select => this.select = select}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> </div> ) } increment = () => { const number = this.select.value * 1 this.props.store.dispatch(actions.increment(number)) } decrement = () => { const number = this.select.value * 1 this.props.store.dispatch(actions.decrement(number)) } }
action-types.js
// action对象的type常量名称模块 export const INCREMENT = 'increment' export const DECREMENT = 'decrement'
action.js
// action creator模块 import { INCREMENT, DECREMENT } from './action-types.js' export const increment = number => ({ type: INCREMENT, number }) export const decrement = number => ({ type: DECREMENT, number })
reducers.js
// 根据旧state和指定action, 处理返回一个新的state import { INCREMENT, DECREMENT } from './action-types.js' export function counter(state = 0, action) { console.log('counter', state, action) switch (action.type) { case INCREMENT: return state + action.number case DECREMENT: return state - action.number default: return state } }
3、引入redux + react-redux <--返回目录
React-Redux的思想:将所有组件分成两大类
1) UI组件
a.只负责 UI 的呈现,不带有任何业务逻辑
b.通过props接收数据(一般数据和函数)
c.不使用任何 Redux 的 API
d.一般保存在components文件夹下
2) 容器组件
a.负责管理数据和业务逻辑,不负责UI的呈现
b.使用 Redux 的 API
c.一般保存在containers文件夹下
改造后项目结构:
index.js
import React from 'react' import ReactDOM from 'react-dom' import { Provider } from 'react-redux' import App from './containters/app.jsx' import store from './redux/store.js' ReactDOM.render( (<Provider store={store}> <App /> </Provider>), document.getElementById('root') )
app.jsx
/* 包含Counter组件的容器组件 */ import React from 'react' // 引入连接函数 import { connect } from 'react-redux' // 引入action函数 import { increment, decrement } from '../redux/actions.js' import Counter from '../components/counter.jsx' // 向外暴露连接App组件的包装组件 export default connect( state => ({ count: state }), { increment, decrement } )(Counter)
counter.jsx
/* UI组件: 不包含任何redux API */ import React from 'react' import PropTypes from 'prop-types' export default class Counter extends React.Component { static propTypes = { count: PropTypes.number.isRequired, increment: PropTypes.func.isRequired, decrement: PropTypes.func.isRequired } render() { return ( <div> <p>click {this.props.count} times</p> <select ref={select => this.select = select}> <option value="1">1</option> <option value="2">2</option> <option value="3">3</option> </select> <button onClick={this.increment}>+</button> <button onClick={this.decrement}>-</button> </div> ) } increment = () => { const number = this.select.value * 1 this.props.increment(number) } decrement = () => { const number = this.select.value * 1 this.props.decrement(number) } }
action-types.js
// action对象的type常量名称模块 export const INCREMENT = 'increment' export const DECREMENT = 'decrement'
actions.js
// action creator模块 import { INCREMENT, DECREMENT } from './action-types.js' export const increment = number => ({ type: INCREMENT, number }) export const decrement = number => ({ type: DECREMENT, number })
reducers.js
// 根据旧state和指定action, 处理返回一个新的state import { INCREMENT, DECREMENT } from './action-types.js' export function counter(state = 0, action) { console.log('counter', state, action) switch (action.type) { case INCREMENT: return state + action.number case DECREMENT: return state - action.number default: return state } }
store.js
import { createStore } from 'redux' import { counter } from './reducers.js' // 根据counter函数创建store对象 const store = createStore(counter) export default store