React 本身只是一个 DOM 的抽象层,使用组件来构建虚拟的 DOM。在开发大的应用的时候,则面临着如下需要解决的问题:
组件之间会发生三种通信:
对此 React 只提供了一种通信手段:传参,对于大应用通信来说很不方便。
import React from 'react';
import './style.css';
export default function App() {
return (
<div>
<Father />
</div>
);
}
class Son extends React.Component {
render() {
return <input />;
}
}
class Father extends React.Component {
render() {
return (
<div>
<Son />
<p>这里显示Son组件的内容</p>
</div>
);
}
}
对于这个例子,父组件该如何拿到子组件的值?
import React from 'react';
import './style.css';
export default function App() {
return (
<div>
<Father />
</div>
);
}
class Son extends React.Component {
render() {
return <input onChange={this.props.onChange} />;
}
}
class Father extends React.Component {
constructor() {
super();
this.state = {
son: '',
};
}
changeHandler(e) {
this.setState({
son: e.target.value,
});
}
render() {
return (
<div>
<Son onChange={this.changeHandler.bind(this)} />
<p>这里显示Son组件的内容: {this.state.son}</p>
</div>
);
}
}
目前流行的数据流方案:
对于 React 来说,最流行的社区 React 应用架构方案如下:
缺点是需要引入多个库,项目结构复杂
dva 是一个 React 应用框架,将上面三个 React 工具库包装在一起,简化了 API ,让开发更加方便快捷。
dva = React-Router + Redux + Redux-saga
import dva from 'dva';
const App = () => <div>Hello dva</div>;
// 创建应用
const app = dva();
// 注册视图
app.router(() => <App />);
// 启动应用
app.start('#root');
以下部分可以结合Redux进行阅读
State 是储存数据的地方,收到 Action 以后,会更新数据。
View 就是 React 组件构成的 UI 层,从 State 取数据后,渲染成 HTML 代码。只要 State 有变化,View 就会自动更新。
Action 是用来描述 UI 层事件的一个对象。
{
type: 'click-submit-button',
payload: this.form.data
}
connect 是一个函数,绑定 State 到 View。
import { connect } from 'dva';
function mapStateToProps(state) {
return { todos: state.todos };
}
connect(mapStateToProps)(App);
connect 方法返回的也是一个 React 组件,通常称为容器组件。因为它是原始 UI 组件的容器,即在外面包了一层 State。
connect 方法传入的第一个参数是 mapStateToProps 函数,mapStateToProps 函数会返回一个对象,用于建立 State 到 Props 的映射关系。
dispatch 是一个函数方法,用来将 Action 发送给 State。
dispatch({
type: 'click-submit-button',
payload: this.form.data
})
dispatch 方法从哪里来?被 connect 的 Component 会自动在 props 中拥有 dispatch 方法。
Reducer 是 Action 处理器,用来处理同步操作,可以看做是 state 的计算器。它的作用是根据 Action,从上一个 State 算出当前 State。
// count +1
function add(state) {
return state + 1;
}
// 往 [] 里添加一个新 todo
function addTodo(state, action) {
return [...state, action.payload];
}
// 往 { todos: [], loading: true } 里添加一个新 todo,并标记 loading 为 false
function addTodo(state, action) {
return {
...state,
todos: state.todos.concat(action.payload),
loading: false,
};
}
Action 处理器,处理异步动作,基于 Redux-saga 实现。Effect 指的是副作用。根据函数式编程,计算以外的操作都属于 Effect,典型的就是 I/O 操作、数据库读写。
function *addAfter1Second(action, { put, call }) {
yield call(delay, 1000);
yield put({ type: 'add' });
}
Effect 是一个 Generator 函数,内部使用 yield 关键字,标识每一步的操作(不管是异步或同步)。
dva 提供多个 effect 函数内部的处理函数,比较常用的是 call 和 put。
import dva, { connect } from 'dva';
const App = () => <div>Hello dva</div>;
// 创建应用
const app = dva();
// 注册Model
app.model({
namespace: 'count',
state: 0,
reducers: {
add(state) {
return state + 1;
},
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
});
// 注册视图
app.router(() => <App />);
// 启动应用
app.start('#root');
dva 提供 app.model 这个对象,所有的应用逻辑都定义在它上面。
const app = dva();
// 新增这一行
app.model({ /**/ });
app.router(() => <App />);
app.start('#root');
{
namespace: 'count',
state: 0,
reducers: {
add(state) { return state + 1 },
},
effects: {
*addAfter1Second(action, { call, put }) {
yield call(delay, 1000);
yield put({ type: 'add' });
},
},
}
属性
写一个列表,包含删除按钮,点删除按钮后延迟 1 秒执行删除。
以下代码写在index.js
中
import React from 'react';
import dva, { connect } from 'dva';
// 1. 创建应用
const app = dva();
import React from 'react';
import dva, { connect } from 'dva';
// 1. 创建应用
const app = dva();
// 2. 注册Model
app.model({
namespace: 'todoList',
state: [
{
id: 1,
name: 'list1',
},
{
id: 2,
name: 'list2',
},
],
reducers: {
delete(todoList, action) {
return todoList.filter((item) => item.id !== action.payload.id);
},
},
});
reducers 中的 delete 方法,传入两个参数,前一个为 state 值,后一个为 action 操作
import React from 'react';
import dva, { connect } from 'dva';
// 1. 创建应用
const app = dva();
// 2. 注册Model
app.model({
namespace: 'todoList',
state: [
{
id: 1,
name: 'list1',
},
{
id: 2,
name: 'list2',
},
],
reducers: {
delete(todoList, action) {
return todoList.filter((item) => item.id !== action.payload.id);
},
},
});
// 3. 创建View
const App = connect(({ todoList }) => ({
todoList,
}))(function view(props) {
return (props.todoList || []).map((item) => {
return (
<div>
<h2>{item.name}</h2>
<button
onClick={() => {
props.dispatch({
type: 'todoList/delete',
payload: item,
});
}}
>
删除
</button>
</div>
);
});
});
import React from 'react';
import dva, { connect } from 'dva';
// 1. 创建应用
const app = dva();
// 2. 注册Model
app.model({
namespace: 'todoList',
state: [
{
id: 1,
name: 'list1',
},
{
id: 2,
name: 'list2',
},
],
reducers: {
delete(todoList, action) {
return todoList.filter((item) => item.id !== action.payload.id);
},
},
});
// 3. 创建View
const App = connect(({ todoList }) => ({
todoList,
}))(function view(props) {
return (props.todoList || []).map((item) => {
return (
<div>
<h2>{item.name}</h2>
<button
onClick={() => {
props.dispatch({
type: 'todoList/delete',
payload: item,
});
}}
>
删除
</button>
</div>
);
});
});
// 4. 注册视图
app.router(() => <App />);
import React from 'react';
import dva, { connect } from 'dva';
// 1. 创建应用
const app = dva();
// 2. 注册Model
app.model({
namespace: 'todoList',
state: [
{
id: 1,
name: 'list1',
},
{
id: 2,
name: 'list2',
},
],
reducers: {
delete(todoList, action) {
return todoList.filter((item) => item.id !== action.payload.id);
},
},
});
// 3. 创建View
const App = connect(({ todoList }) => ({
todoList,
}))(function view(props) {
return (props.todoList || []).map((item) => {
return (
<div>
<h2>{item.name}</h2>
<button
onClick={() => {
props.dispatch({
type: 'todoList/delete',
payload: item,
});
}}
>
删除
</button>
</div>
);
});
});
// 4. 注册视图
app.router(() => <App />);
// 5. 启动应用
app.start('#root');