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; }