1:安装
npm i redux npm i react-redux
2:配置index.js
import React from \'react\'; import ReactDOM from \'react-dom/client\'; import TodoList from \'./todo_list/TodoList\'; import store from \'./store\'; import { Provider } from \'react-redux\'; const App = () => ( <Provider store={store}> <TodoList /> </Provider> ) const root = ReactDOM.createRoot(document.getElementById(\'root\')); root.render( // 严格模式:控制台会出现调用两次问题 // 严格模式检查只在开发模式下运行,不会与生产模式冲突。 // <React.StrictMode><TodoList /></React.StrictMode> <App /> );
3:根目录新建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 = { inputVal: \'\', list: [] } // reducer 可以接收state,但是绝对不能修改state export default (state = defaultState, action) => { if(action.type === \'change_input_val\'){ let newState = JSON.parse(JSON.stringify(state)); newState.inputVal = action.value; console.log(newState); return newState; } if(action.type === \'submit_input\'){ let newState = JSON.parse(JSON.stringify(state)); newState.list.push(newState.inputVal) newState.inputVal = \'\'; console.log(newState); return newState; } if(action.type === \'submit_delect_item\'){ let newState = JSON.parse(JSON.stringify(state)); newState.list.splice(action.index, 1); return newState; } return state; }
组件中使用:
DEMO-todolist:
TodoList.js
import { Component, Fragment } from \"react\"; import TodoItem from \"./TodoItem\"; import \'./TodoList.css\' import { connect } from \'react-redux\'; class TodoList extends Component{ render() { return ( <Fragment> <div className=\"input-box\"> <label htmlFor=\"inputId\">输入框聚焦</label> <input id=\"inputId\" value={this.props.inputVal} onChange={this.props.headleInputChange}/> <button onClick={this.props.headleButtonClick}>提交</button> </div> <ul className=\"todo-ul\"> { this.getTodoItem() } </ul> </Fragment> ) } // 获取数组dom getTodoItem(){ return this.props.list.map((item, index) => { return ( <TodoItem key={index} index={index} content={item} delItemClick={this.props.delItemClick} /> ) }) } } const mapStateToProps = (state) =>{ return { inputVal: state.inputVal, list: state.list } } const mapDispatchToProps = (dispatch) =>{ return { // 输入框监听改变 headleInputChange(e){ const action = { type: \'change_input_val\', value: e.target.value } dispatch(action) }, // 点击提交按钮 headleButtonClick(){ const action = { type: \'submit_input\' } dispatch(action); }, // 删除列表项 delItemClick(index){ const action = { type: \'submit_delect_item\', index: index } dispatch(action) } } } export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
TodoItem.js
import { Component } from \"react\"; import { PropTypes } from \'prop-types\' class TodoItem extends Component{ constructor(props){ super(props) this.sonItemClick = this.sonItemClick.bind(this); } render(){ const { content } = this.props; return <li onClick={this.sonItemClick}>{content}</li> } sonItemClick(){ let {delItemClick, index} = this.props; delItemClick(index) } } // 设置props传入的数据格式 TodoItem.propTypes = { content: PropTypes.string.isRequired, delItemClick: PropTypes.func, index: PropTypes.oneOfType([PropTypes.number, PropTypes.string]) } //父组件未传参时设置默认值 TodoItem.defaultProps = { content: \'默认值\' } export default TodoItem;
TodoList.css
.input-box{ display: flex; align-items: center; } .input-box label{ cursor: pointer; } .input-box input, .input-box button{ box-sizing: border-box; border: 1px solid #ccc; height: 30px; } .input-box button{ cursor: pointer; } .todo-ul li{ cursor: pointer; }