前面我们了解了redux 以及redux 的中间件 redux-thunk,redux-saga。
下面,我们来继续了解一下 react-redux。react-redux 是一个第三方模块,能够帮助我们在react 中更方便的使用redux。
好啦,我们现在用react-redux 重新写一个todolist。之前的store文件夹,和src 里面组件代码都可以删掉了。
我们先来安装react-redux
npm install react-redux --save
然后先在src 下面创建一个组件FinalToDoList.js 文件,然后在index.js 中引入。FinalToDoList.js 部分代码如下。
class App extends Component {
render() {
return (
<div>
<div>
<input />
<button>提交</button>
</div>
<ul>
<li>Alice</li>
<li>Flower</li>
</ul>
</div>
);
}
}
然后,我们在src 下创建一个目录,store,在store下新建index.js 与reducer.js 代码如下。
先是index.js
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
export default store;
然后是 reducer.js
const defaultState = {
inputValue: '',
list: []
}
export default (state = defaultState, action) => {
return state;
}
之前我们在组件中的使用大概是像下面这样
import React, { Component } from 'react';
import store from './store/index';
class App extends Component {
constructor(props) {
super(props);
this.state = store.getState();
}
render() {
return (
<div>
<div>
<input value={this.state.inputValue}/>
<button>提交</button>
</div>
<ul>
<li>Alice</li>
<li>Flower</li>
</ul>
</div>
);
}
}
export default App;
下面,我们使用react-redux
首先在src下的index,做下面的修改,使用react-redux 中的核心API Provider,如下。将Provider 绑定了 store属性,意思是Provider 里的所有子组件都有能力获得store 中的内容了。
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import store from './store/index';
const Whole = (
<Provider store={store}>
<App />
<A></A>
<b />
</Provider>
);
ReactDOM.render(Whole, document.getElementById('root'));
好现在,我们回到我们的组件里来,之前获取数据是通过store.dispatch 获取的,现在就很简单就能获取了。如下。
【最后一行代码是指,这个组件与store 做连接。mapStateToProps 是连接规则,将store 中数据映射到props中去。 】
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
render() {
return (
<div>
<div>
<input value={this.props.inputValue}/>
<button>提交</button>
</div>
<ul>
<li>Alice</li>
<li>Flower</li>
</ul>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue
}
}
export default connect(mapStateToProps,null)(App);
好的,接下来,我们来写一下input 的change 方法,如下。
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
render() {
return (
<div>
<div>
<input
value={this.props.inputValue}
onChange={this.props.changeInputValue}
/>
<button>提交</button>
</div>
<ul>
<li>Alice</li>
<li>Flower</li>
</ul>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue
}
}
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue (e) {
const action = {
type: "change_input_value",
value: e.target.value
};
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
然后去reducer.js 中增加一个处理,代码如下。
const defaultState = {
inputValue: 'hello world',
list: []
}
export default (state = defaultState, action) => {
if (action.type === "change_input_value") {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
return state;
}
下面,我们完善todolist 的功能。
如下是 组件的代码。
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
render() {
return (
<div>
<div>
<input
value={this.props.inputValue}
onChange={this.props.changeInputValue}
/>
<button onClick={this.props.handleClick}>提交</button>
</div>
<ul>
{
this.props.list.map((item,index) => {
return (<li
key={index}
onClick={() => this.props.handleDelete(index)}
>
{item}</li>)
})
}
</ul>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue,
list: state.list
}
}
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue (e) {
const action = {
type: "change_input_value",
value: e.target.value
};
dispatch(action);
},
handleClick () {
const action = {
type: "add_input_value"
};
dispatch(action);
},
handleDelete (index) {
const action = {
type: "delete_item",
value: index
};
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
下面是reducer.js 代码。
const defaultState = {
inputValue: '',
list: ['Alice', 'Bob']
}
export default (state = defaultState, action) => {
if (action.type === "change_input_value") {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
if (action.type === "add_input_value") {
const newState = JSON.parse(JSON.stringify(state));
newState.list.push(newState.inputValue);
newState.inputValue = "";
return newState;
}
if (action.type === "delete_item") {
const newState = JSON.parse(JSON.stringify(state));
newState.list.splice(action.value,1);
return newState;
}
return state;
}
下面,我们把组件代码,改的优雅一些吧。
import React, { Component } from 'react';
import { connect } from 'react-redux';
class App extends Component {
render() {
const {inputValue, list, handleClick, changeInputValue} = this.props;
return (
<div>
<div>
<input
value={inputValue}
onChange={changeInputValue}
/>
<button onClick={handleClick}>提交</button>
</div>
<ul>
{
list.map((item,index) => {
return (<li
key={index}
onClick={() => this.props.handleDelete(index)}
>
{item}</li>)
})
}
</ul>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue,
list: state.list
}
}
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue (e) {
const action = {
type: "change_input_value",
value: e.target.value
};
dispatch(action);
},
handleClick () {
const action = {
type: "add_input_value"
};
dispatch(action);
},
handleDelete (index) {
const action = {
type: "delete_item",
value: index
};
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
然后,组件只有一个render 方法,因此,我们可以把它改为无状态组件,如下。
import React, { Component } from 'react';
import { connect } from 'react-redux';
const App = (props) => {
const {inputValue, list, handleClick, changeInputValue, handleDelete} = props;
return (
<div>
<div>
<input
value={inputValue}
onChange={changeInputValue}
/>
<button onClick={handleClick}>提交</button>
</div>
<ul>
{
list.map((item,index) => {
return (<li
key={index}
onClick={() => handleDelete(index)}
>
{item}</li>)
})
}
</ul>
</div>
);
}
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue,
list: state.list
}
}
const mapDispatchToProps = (dispatch) => {
return {
changeInputValue (e) {
const action = {
type: "change_input_value",
value: e.target.value
};
dispatch(action);
},
handleClick () {
const action = {
type: "add_input_value"
};
dispatch(action);
},
handleDelete (index) {
const action = {
type: "delete_item",
value: index
};
dispatch(action);
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App);
Done.