// index.js import React, { useReducer } from 'react' import { render } from 'react-dom' import { HashRouter as Router, Route, Redirect, Switch } from 'react-router-dom' import Context from './context.js' import Home from './component/home.js' import List from './component/list.js' import rootReducer from './reducer' import '../public/css/index.css' const Root = () => { const initState = { list: [ { id: 0, txt: 'webpack 4' }, { id: 1, txt: 'react' }, { id: 2, txt: 'redux' }, ] }; // useReducer映射出state,dispatch const [state, dispatch] = useReducer(rootReducer, initState); return <Context.Provider value={{ state, dispatch }}> <Router> <Switch> <Route exact path="https://www.jb51.net/" component={Home} /> <Route exact path="/list" component={List} /> <Route render={() => (<Redirect to="https://www.jb51.net/" />)} /> </Switch> </Router> </Context.Provider> } render( <Root />, document.getElementById('root') )
constants.js, action.js 和 reducer.js 与之前的写法是一致的。
// constants.js export const ADD_COMMENT = 'ADD_COMMENT' export const REMOVE_COMMENT = 'REMOVE_COMMENT' // action.js import { ADD_COMMENT, REMOVE_COMMENT } from './constants' export function addComment(comment) { return { type: ADD_COMMENT, comment } } export function removeComment(id) { return { type: REMOVE_COMMENT, id } }
list.js
import { ADD_COMMENT, REMOVE_COMMENT } from '../constants.js' const list = (state = [], payload) => { switch (payload.type) { case ADD_COMMENT: if (Array.isArray(payload.comment)) { return [...state, ...payload.comment]; } else { return [...state, payload.comment]; } case REMOVE_COMMENT: return state.filter(i => i.id != payload.id); default: return state; } }; export default list
reducer.js
import { combineReducers } from 'redux' import list from './list.js' const rootReducer = combineReducers({ list, //user }); export default rootReducer
最大区别的地方就是 component 组件,基于 函数式 ,内部的表达式就像是即插即用的插槽,可以很方便的抽取出通用的组件,然后从外部引用。相比之前的 面向对象 方式,我觉得 函数表达式 更受前端开发者欢迎。
useContext 获取全局的 state
useRef 代替之前的 ref
useState 代替之前的 state
useEffect则可以代替之前的生命周期钩子函数
//监控数组中的参数,一旦变化就执行 useEffect(() => { updateData(); },[id]); //不传第二个参数的话,它就等价于每次componentDidMount和componentDidUpdate时执行 useEffect(() => { updateData(); }); //第二个参数传空数组,等价于只在componentDidMount和componentWillUnMount时执行, //第一个参数中的返回函数用于执行清理功能 useEffect(() => { initData(); reutrn () => console.log('componentWillUnMount cleanup...'); }, []);
最后就是实现具体界面和业务逻辑的组件了,下面是其中的List组件
// list.js import React, { useRef, useState, useContext } from 'react' import { bindActionCreators } from 'redux' import { Link } from 'react-router-dom' import Context from '../context.js' import * as actions from '../action.js' import Dialog from './dialog.js' import './list.scss' const List = () => { const ctx = useContext(Context);//获取全局状态state const { user, list } = ctx.state; const [visible, setVisible] = useState(false); const [rid, setRid] = useState(''); const inputRef = useRef(null); const { removeComment, addComment } = bindActionCreators(actions, ctx.dispatch); const confirmHandle = () => { setVisible(false); removeComment(rid); } const cancelHandle = () => { setVisible(false); } const add = () => { const input = inputRef.current, val = input.value.trim(); if (!val) return; addComment({ id: Math.round(Math.random() * 1000000), txt: val }); input.value = ''; } return <> <div styleName="form"> <h3 styleName="sub-title">This is list page</h3> <div> <p>hello, {user.name} !</p> <p>your email is {user.email} !</p> <p styleName="tip">please add and remove the list item !!</p> </div> <ul> { list.map(l => <li key={l.id}>{l.txt}<i className="icon-minus" title="remove item" onClick={() => { setVisible(true); setRid(l.id); }}></i></li>) } </ul> <input ref={inputRef} type="text" /> <button onClick={add} title="add item">Add Item</button> <Link styleName="link" to="https://www.jb51.net/">redirect to home</Link> </div> <Dialog visible={visible} confirm={confirmHandle} cancel={cancelHandle}>remove this item ?</Dialog> </> } export default List;
项目代码