React 脚手架
01-脚手架自带文件
可以避免同名 css 被覆盖的问题,后引入的组件样式会覆盖同名的前面的样式
index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
//引入组件
import App from "./App.jsx";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import Hello from "./components/Hello";
import Welcome from "./components/Welcome";
export default class App extends Component {
render() {
return (
<div>
<Hello />
<Welcome />
</div>
);
}
}
Hello.jsx
import React, { Component } from "react";
import hello from "./index.module.css";
export default class Hello extends Component {
render() {
return (
<div className={hello.hello}>
<h2>Hello</h2>
</div>
);
}
}
Welcome.jsx
import React, { Component } from "react";
import "./index.css";
export default class Welcome extends Component {
render() {
return (
<div className="welcome">
<h1>Welcome</h1>
</div>
);
}
}
03-配置代理 setupProxy
setupProxy.js
const proxy = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
proxy("/api1", {
// 遇见api1前缀的请求就会触发该代理配置
targer: "http://localhost:5000", // 请求转发给谁
changeOrigin: true, // 控制服务器收到的响应头重host字段的值
/*
changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
changeOrigin默认值为false,但我们一般将changeOrigin值设为true
*/
pathRewrite: { "^/api1": "" }, //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
})
);
app.use(
proxy("/api2", {
targer: "http://localhost:5001",
changeOrigin: true,
pathRewrite: { "^/api2": "" },
})
);
};
04-消息订阅与发布
Hello.jsx
import React, { Component } from "react";
import PubSub from "pubsub-js";
export default class Hello extends Component {
talkWecome = () => {
PubSub.publish("talkWecome", { info: "hello发送数据给welcome" });
};
render() {
return (
<div>
<h2>Hello</h2>
<button onClick={this.talkWecome}>告诉welcome</button>
</div>
);
}
}
Welcome.jsx
import React, { Component } from "react";
import PubSub from "pubsub-js";
export default class Welcome extends Component {
state = { info: "" };
componentDidMount() {
this.token = PubSub.subscribe("talkWecome", (_, data) => {
this.setState(data);
});
}
componentWillUnmount() {
PubSub.unsubscribe(this.token);
}
render() {
return (
<div className="welcome">
<h1>Welcome</h1>
<h2>{this.state.info}</h2>
</div>
);
}
}
05-路由的基本使用
index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入组件
import App from "./App.jsx";
ReactDOM.render(
// 一个项目只允许有一个 BrowserRouter
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Link, BrowserRouter, Route } from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
{/* 一个项目只允许有一个 BrowserRoute,把这个写到index.js里面 */}
{/* 注册跳转标签 */}
<Link to="/about"> About </Link>
<Link to="/home"> Home </Link>
{/* 注册路由 */}
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
</div>
);
}
}
About.jsx
import React, { Component } from "react";
export default class About extends Component {
render() {
return (
<div style={{ padding: "10px" }}>
<h1>React Router Demo</h1>
<div style={{ border: "1px solid red" }}>
<h2>导航区</h2>
<div>
<a style={{ float: "left", marginRight: "10px", color: "red" }}>
About
</a>
<a>Home</a>
</div>
</div>
<div style={{ border: "1px solid green", marginTop: "10px" }}>
<h2>展示区</h2>
<h2>About</h2>
</div>
</div>
);
}
}
Home.jsx
import React, { Component } from "react";
export default class Home extends Component {
render() {
return (
<div style={{ padding: "10px" }}>
<h1>React Router Demo</h1>
<div style={{ border: "1px solid red" }}>
<h2>导航区</h2>
<div>
<a style={{ float: "left", marginRight: "10px" }}>About</a>
<a style={{ color: "red" }}>Home</a>
</div>
</div>
<div style={{ border: "1px solid green", marginTop: "10px" }}>
<h2>展示区</h2>
<h2>Home</h2>
</div>
</div>
);
}
}
06-NavLink 的使用
index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入组件
import App from "./App.jsx";
ReactDOM.render(
// 一个项目只允许有一个 BrowserRouter
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Link, NavLink, BrowserRouter, Route } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Hello from "./components/Hello";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
{/* 一个项目只允许有一个 BrowserRoute,把这个写到index.js里面 */}
{/* 注册跳转标签 */}
<NavLink activeClassName="demo" to="/about">
About
</NavLink>
<NavLink activeClassName="demo" to="/home">
Home
</NavLink>
{/* 注册路由 */}
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
{/* <Hello a={123}/> */}
</div>
);
}
}
About.jsx
import React, { Component } from "react";
export default class About extends Component {
render() {
return (
<div style={{ padding: "10px" }}>
<h1>React Router Demo</h1>
<div style={{ border: "1px solid red" }}>
<h2>导航区</h2>
<div>
<a style={{ float: "left", marginRight: "10px", color: "red" }}>
About
</a>
<a>Home</a>
</div>
</div>
<div style={{ border: "1px solid green", marginTop: "10px" }}>
<h2>展示区</h2>
<h2>About</h2>
</div>
</div>
);
}
}
Home.jsx
import React, { Component } from "react";
export default class Home extends Component {
render() {
return (
<div style={{ padding: "10px" }}>
<h1>React Router Demo</h1>
<div style={{ border: "1px solid red" }}>
<h2>导航区</h2>
<div>
<a style={{ float: "left", marginRight: "10px" }}>About</a>
<a style={{ color: "red" }}>Home</a>
</div>
</div>
<div style={{ border: "1px solid green", marginTop: "10px" }}>
<h2>展示区</h2>
<h2>Home</h2>
</div>
</div>
);
}
}
07-封装 MyNavLink
03-React-cli\07-封装 MyNavLink\components\MyNavLink\index.jsx
import React, { Component } from "react";
import { NavLink } from "react-router-dom";
export default class MyNavLink extends Component {
render() {
console.log(this.props);
return (
<div>
<NavLink {...this.props} activeClassName="demo" to={this.props.to} />
</div>
);
}
}
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Link, NavLink, BrowserRouter, Route } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import Hello from "./components/Hello";
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
{/* 一个项目只允许有一个 BrowserRoute,把这个写到index.js里面 */}
{/* 注册跳转标签 */}
{/* 接收标签体内容 */}
{/* 标签体内容也是一个特殊的标签属性 在props里面的 children */}
<MyNavLink to="/about">about</MyNavLink>
<MyNavLink to="/home">home</MyNavLink>
{/* 注册路由 */}
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
{/* <Hello a={123}/> */}
</div>
);
}
}
08-Switch 的使用
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Link, BrowserRouter, Route } from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
import Test from "./components/Test";
import { Switch } from "react-router-dom/cjs/react-router-dom.min";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
{/* 一个项目只允许有一个 BrowserRoute,把这个写到index.js里面 */}
{/* 注册跳转标签 */}
<Link to="/about"> About </Link>
<Link to="/home"> Home </Link>
{/* 注册路由 */}
{/* 这个组件只会让路由注册一个,匹配到后下面的组件就不展示了 */}
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<Route path="/home" component={Test} />
</Switch>
</div>
);
}
}
09-解决样式丢失问题
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Link, NavLink, HashRouter, Route } from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
import Test from "./components/Test";
import MyNavLink from "./components/MyNavLink";
import { Switch } from "react-router-dom/cjs/react-router-dom.min";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
{/* 这样写法会出现样式问题,因为 /LGQ/ 会被浏览器当做路径去处理 */}
{/* 解决方案 */}
{/* 1. <link href="/css/bootstrap.css" rel="stylesheet"> */}
{/* 2. <link href="%PUBLIC_URL%/css/bootstrap.css" rel="stylesheet"> */}
{/* 3. 修改 BrowserRouter 为 HashRouter */}
<MyNavLink to="/LGQ/about">About</MyNavLink>
<MyNavLink to="/LGQ/home">Home</MyNavLink>
{/* 注册路由 */}
<Switch>
<Route path="/LGQ/about" component={About} />
<Route path="/LGQ/home" component={Home} />
<Route path="/LGQ/home" component={Test} />
</Switch>
{/* <Hello a={123}/> */}
</div>
);
}
}
10-模糊匹配与精准匹配
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Link, NavLink, HashRouter, Route } from "react-router-dom";
import About from "./components/About";
import Home from "./components/Home";
import Test from "./components/Test";
import MyNavLink from "./components/MyNavLink";
import { Switch } from "react-router-dom/cjs/react-router-dom.min";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
{/* 模糊匹配路由: Route 要的 MyNavLink 必须一个不能少,但是可以多 */}
{/* to="/home/a/b" path="/home" 可以 */}
{/* to="/home/" path="/homea/b" 不可以 */}
{/* 严格匹配路由: exact */}
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home/a/b">Home</MyNavLink>
{/* 注册路由 */}
<Switch>
<Route exact path="/about" component={About} />
<Route exact path="/home" component={Home} />
<Route exact path="/test" component={Test} />
</Switch>
</div>
);
}
}
11-嵌套路由的使用
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import { Route, Redirect } from "react-router-dom";
import About from "./pages/About";
import Home from "./pages/Home";
import MyNavLink from "./components/MyNavLink";
import { Switch } from "react-router-dom/cjs/react-router-dom.min";
export default class App extends Component {
render() {
return (
<div>
<h1>我是APP</h1>
<MyNavLink to="/about">About</MyNavLink>
<MyNavLink to="/home">Home</MyNavLink>
{/* 注册路由 */}
<Switch>
<Route path="/about" component={About} />
<Route path="/home" component={Home} />
<Redirect to="/about"></Redirect>
</Switch>
</div>
);
}
}
Home.jsx
import React, { Component } from "react";
import MyNavLink from "../../components/MyNavLink";
import { Route } from "react-router-dom";
import { Switch } from "react-router-dom/cjs/react-router-dom.min";
import Message from "./Message";
import News from "./News";
export default class Home extends Component {
render() {
return (
<div style={{ padding: "10px" }}>
<MyNavLink to="/home/message">Message</MyNavLink>
<MyNavLink to="/home/news">News</MyNavLink>
<div style={{ border: "1px solid green", marginTop: "10px" }}>
<h4>展示区</h4>
<h4>Home</h4>
<Switch>
<Route path="/home/message" component={Message} />
<Route path="/home/news" component={News} />
</Switch>
</div>
</div>
);
}
}
Message.jsx
import React, { Component } from "react";
export default class Message extends Component {
render() {
return (
<div>
<ul>
<li>Message 1</li>
<li>Message 2</li>
<li>Message 3</li>
<li>Message 4</li>
</ul>
</div>
);
}
}
News.jsx
import React, { Component } from "react";
export default class News extends Component {
render() {
return (
<div>
<ul>
<li>News 1</li>
<li>News 2</li>
<li>News 3</li>
<li>News 3</li>
</ul>
</div>
);
}
}
12-路由组件传递 params 参数
Message.jsx
import React, { Component } from "react";
import Detail from "./Detail";
import { Link, Route } from "react-router-dom/cjs/react-router-dom.min";
export default class Message extends Component {
state = {
messages: [
{ id: 1, title: "message1" },
{ id: 2, title: "message2" },
{ id: 3, title: "message3" },
{ id: 4, title: "message4" },
],
};
render() {
return (
<div>
{this.state.messages.map((el) => {
return (
<li key={el.id}>
{/* 1. Link 携带 params 参数 */}
<Link to={`/home/message/detail/${el.id}/${el.title}`}>
{el.title}
</Link>
</li>
);
})}
{/* 1. Route 声明接收 params 参数 */}
<Route path="/home/message/detail/:id/:title" component={Detail} />
</div>
);
}
}
Detail.jsx
import React, { Component } from "react";
const data = {
1: "你好,中国",
2: "你好,上海",
3: "你好,杭州",
4: "你好,郑州",
};
export default class Detail extends Component {
render() {
console.log(this.props);
// 1. 接受 Params 参数
// {
// "match": {
// "path": "/home/message/detail/:id/:title",
// "url": "/home/message/detail/3/Message3",
// "isExact": true,
// "params": {
// "id": "3",
// "title": "Message3"
// }
// }
// }
return (
<div>
<p>ID: {this.props.match.params.id}</p>
<p>Title: {this.props.match.params.title}</p>
<p>Content: {data[this.props.match.params.id]}</p>
</div>
);
}
}
13-路由组件传递 search 参数
Message.jsx
import React, { Component } from "react";
import Detail from "./Detail";
import { Link, Route } from "react-router-dom/cjs/react-router-dom.min";
export default class Message extends Component {
state = {
messages: [
{ id: 1, title: "message1" },
{ id: 2, title: "message2" },
{ id: 3, title: "message3" },
{ id: 4, title: "message4" },
],
};
render() {
return (
<div>
{this.state.messages.map((el) => {
return (
<li key={el.id}>
{/* 1. Link 携带 params 参数 */}
{/* <Link to={`/home/message/detail/${el.id}/${el.title}`}>
{el.title}
</Link> */}
{/* 2. Link 携带 search 参数 */}
<Link to={`/home/message/detail/?id=${el.id}&title=${el.title}`}>
{el.title}
</Link>
</li>
);
})}
{/* 1. Route 声明接收 params 参数 */}
{/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
{/* 2. search 参数无需声明接收 */}
<Route path="/home/message/detail" component={Detail} />
</div>
);
}
}
Detail.jsx
import React, { Component } from "react";
import qs from "querystring";
const data = {
1: "你好,中国",
2: "你好,上海",
3: "你好,杭州",
4: "你好,郑州",
};
export default class Detail extends Component {
render() {
console.log(this.props);
// 1. 接受 params 参数
// {
// "match": {
// "path": "/home/message/detail/:id/:title",
// "url": "/home/message/detail/3/Message3",
// "isExact": true,
// "params": {
// "id": "3",
// "title": "Message3"
// }
// }
// }
// return (
// <div>
// <p>ID: {this.props.match.params.id}</p>
// <p>Title: {this.props.match.params.title}</p>
// <p>Content: {data[this.props.match.params.id]}</p>
// </div>
// );
// 2. 接受 search 参数
// key=value&key=value 这种形式是 urlencoded编码
const { id, title } = qs.parse(this.props.location.search.slice(1));
return (
<div>
<p>ID: {id}</p>
<p>Title: {title}</p>
<p>Content: {data[id]}</p>
</div>
);
}
}
14-路由组件传递 state 参数
Message.jsx
import React, { Component } from "react";
import Detail from "./Detail";
import { Link, Route } from "react-router-dom/cjs/react-router-dom.min";
export default class Message extends Component {
state = {
messages: [
{ id: 1, title: "message1" },
{ id: 2, title: "message2" },
{ id: 3, title: "message3" },
{ id: 4, title: "message4" },
],
};
render() {
return (
<div>
{this.state.messages.map((el) => {
return (
<li key={el.id}>
{/* 1. Link 携带 params 参数 */}
{/* <Link to={`/home/message/detail/${el.id}/${el.title}`}>
{el.title}
</Link> */}
{/* 2. Link 携带 search 参数 */}
{/* <Link to={`/home/message/detail/?id=${el.id}&title=${el.title}`}>
{el.title}
</Link> */}
{/* 3. Link 携带 state 参数 */}
<Link
to={{
pathname: "/home/message/detail",
state: { id: el.id, title: el.title },
}}
>
{el.title}
</Link>
</li>
);
})}
{/* 1. Route 声明接收 params 参数 */}
{/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
{/* 2. search 参数无需声明接收 */}
{/* <Route path="/home/message/detail" component={Detail} /> */}
{/* 3. state 参数无需声明接收 */}
<Route path="/home/message/detail" component={Detail} />
</div>
);
}
}
Detail.jsx
import React, { Component } from "react";
import qs from "querystring";
const data = {
1: "你好,中国",
2: "你好,上海",
3: "你好,杭州",
4: "你好,郑州",
};
export default class Detail extends Component {
render() {
console.log(this.props);
// 1. 接受 params 参数
// {
// "match": {
// "path": "/home/message/detail/:id/:title",
// "url": "/home/message/detail/3/Message3",
// "isExact": true,
// "params": {
// "id": "3",
// "title": "Message3"
// }
// }
// }
// return (
// <div>
// <p>ID: {this.props.match.params.id}</p>
// <p>Title: {this.props.match.params.title}</p>
// <p>Content: {data[this.props.match.params.id]}</p>
// </div>
// );
// 2. 接受 search 参数
// key=value&key=value 这种形式是 urlencoded编码
// const { id, title } = qs.parse(this.props.location.search.slice(1));
// return (
// <div>
// <p>ID: {id}</p>
// <p>Title: {title}</p>
// <p>Content: {data[id]}</p>
// </div>
// );
// 3. 接受 state 参数
const { id, title } = this.props.location.state;
return (
<div>
<p>ID: {id}</p>
<p>Title: {title}</p>
<p>Content: {data[id]}</p>
</div>
);
}
}
15-路由的 replace 模式
messages.jsx
import React, { Component } from "react";
import Detail from "./Detail";
import { Link, Route } from "react-router-dom/cjs/react-router-dom.min";
export default class Message extends Component {
state = {
messages: [
{ id: 1, title: "message1" },
{ id: 2, title: "message2" },
{ id: 3, title: "message3" },
{ id: 4, title: "message4" },
],
};
render() {
return (
<div>
{this.state.messages.map((el) => {
return (
<li key={el.id}>
{/* 3. Link 携带 state 参数 */}
{/* replace模式就不会留下记录 */}
<Link
replace
to={{
pathname: "/home/message/detail",
state: { id: el.id, title: el.title },
}}
>
{el.title}
</Link>
</li>
);
})}
</div>
);
}
}
16-编程式路由导航
Message.jsx
import React, { Component } from "react";
import Detail from "./Detail";
import { Link, Route } from "react-router-dom/cjs/react-router-dom.min";
export default class Message extends Component {
state = {
messages: [
{ id: 1, title: "message1" },
{ id: 2, title: "message2" },
{ id: 3, title: "message3" },
{ id: 4, title: "message4" },
],
};
pushShow = (el) => {
// push 跳转携带 params 参数
// this.props.history.push(`/home/message/detail/${el.id}/${el.title}`);
// push 跳转携带 search 参数
// this.props.history.push(
// `/home/message/detail/?id=${el.id}&title=${el.title}`
// );
// push 跳转携带 state 参数
this.props.history.push("/home/message/detail", {
id: el.id,
title: el.title,
});
};
replaceShow = (el) => {
// replace 跳转携带params参数
// this.props.history.replace(`/home/message/detail/${el.id}/${el.title}`);
// replace 跳转携带 search 参数
// this.props.history.replace(
// `/home/message/detail/?id=${el.id}&title=${el.title}`
// );
// replace 跳转携带 state 参数
this.props.history.replace("/home/message/detail", {
id: el.id,
title: el.title,
});
};
render() {
return (
<div>
{this.state.messages.map((el) => {
return (
<li key={el.id}>
{/* 1. Link 携带 params 参数 */}
<Link to={`/home/message/detail/${el.id}/${el.title}`}>
{el.title}
</Link>
<button onClick={() => this.pushShow(el)}>push查看</button>
<button onClick={() => this.replaceShow(el)}>replace查看</button>
{/* 2. Link 携带 search 参数 */}
{/* <Link to={`/home/message/detail/?id=${el.id}&title=${el.title}`}>
{el.title}
</Link> */}
{/* 3. Link 携带 state 参数 */}
{/* <Link
to={{
pathname: "/home/message/detail",
state: { id: el.id, title: el.title },
}}
>
{el.title}
</Link> */}
</li>
);
})}
{/* 1. Route 声明接收 params 参数 */}
{/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
{/* 2. search 参数无需声明接收 */}
{/* <Route path="/home/message/detail" component={Detail} /> */}
{/* 3. state 参数无需声明接收 */}
<Route path="/home/message/detail" component={Detail} />
</div>
);
}
}
Detail.jsx
import React, { Component } from "react";
import qs from "querystring";
const data = {
1: "你好,中国",
2: "你好,上海",
3: "你好,杭州",
4: "你好,郑州",
};
export default class Detail extends Component {
render() {
console.log(this.props);
// 1. 接受 params 参数
// {
// "match": {
// "path": "/home/message/detail/:id/:title",
// "url": "/home/message/detail/3/Message3",
// "isExact": true,
// "params": {
// "id": "3",
// "title": "Message3"
// }
// }
// }
// return (
// <div>
// <p>ID: {this.props.match.params.id}</p>
// <p>Title: {this.props.match.params.title}</p>
// <p>Content: {data[this.props.match.params.id]}</p>
// </div>
// );
// 2. 接受 search 参数
// key=value&key=value 这种形式是 urlencoded编码
// const { id, title } = qs.parse(this.props.location.search.slice(1));
// return (
// <div>
// <p>ID: {id}</p>
// <p>Title: {title}</p>
// <p>Content: {data[id]}</p>
// </div>
// );
// 3. 接受 state 参数
const { id, title } = this.props.location.state;
return (
<div>
<p>ID: {id}</p>
<p>Title: {title}</p>
<p>Content: {data[id]}</p>
</div>
);
}
}
17-withRouter 的使用
Header.jsx
import React, { Component } from "react";
import { withRouter } from "react-router-dom/cjs/react-router-dom.min";
class Header extends Component {
back = () => {
this.props.history.goBack();
};
forward = () => {
this.props.history.goForward();
};
go = () => {
this.props.history.back();
};
render() {
console.log(this.props);
return (
<div>
<h1>我是APP</h1>
<button onClick={this.back}>回退</button>
<button onClick={this.forward}>前进</button>
<button onClick={this.go}>go</button>
</div>
);
}
}
// withRouter 可以把一般组件加工成路由组件,让一般组件的props有路由组件的API
// withRouter的返回值是一个新组件
export default withRouter(Header);
18-求和 React 版本
Count.jsx
import React, { Component } from "react";
export default class Count extends Component {
state = { count: 0 };
increment = () => {
const { value } = this.selectNumber;
const count = this.state.count + Number(value);
this.setState({
count,
});
};
decrement = () => {
const { value } = this.selectNumber;
const count = this.state.count - Number(value);
this.setState({
count,
});
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
const count = this.state.count + Number(value);
if (this.state.count % 2 !== 0) {
this.setState({
count,
});
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
const count = this.state.count + Number(value);
setTimeout(() => {
this.setState({
count,
});
}, 500);
};
render() {
return (
<div>
<h1>当前求和为: {this.state.count}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
19-Redux 精简版
Count.jsx
import React, { Component } from "react";
// 引入 store
import store from "../../redux/store";
console.log(store);
export default class Count extends Component {
// componentDidMount() {
// // 检测redux中数据的变化,变化就调用render
// store.subscribe(() => {
// this.setState({});
// });
// }
increment = () => {
const { value } = this.selectNumber;
store.dispatch({ type: "increment", data: value - 0 });
};
decrement = () => {
const { value } = this.selectNumber;
store.dispatch({ type: "decrement", data: value - 0 });
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (store.getState() % 2 !== 0) {
store.dispatch({ type: "increment", data: value - 0 });
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
setTimeout(() => {
store.dispatch({ type: "increment", data: value - 0 });
}, 500);
};
render() {
return (
<div>
<h1>当前求和为: {store.getState()}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
03-React-cli\19-Redux 精简版\redux\count_reducer.js
/**
* 1. 该文件是用于创建一个为 count 组件服务的 reducer, 本质就是一个函数;
* 2. reducer函数会接收两个参数,分别是:之前的状态 preState, 动作对象 action
*/
const initState = 0;
export default function countReducer(preState = initState, action) {
const { type, data } = action;
// console.log(type, data);
switch (type) {
case "increment":
return preState + data;
case "decrement":
return preState - data;
default:
return preState;
}
}
03-React-cli\19-Redux 精简版\redux\store.js
// 该文件专门用于暴露一个store对象, 整个应用只有一个store;
// 引入createStore,专门用于创建store对象
import { createStore } from "redux";
// 引入为 count 组件服务的 reducer
import countReducer from "./count_reducer";
export default createStore(countReducer);
20-Redux 完整版
Count.jsx
import React, { Component } from "react";
// 引入 store
import store from "../../redux/store";
import {
createIncrementAction,
createDecrementAction,
} from "../../redux/count_action";
console.log(store);
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
store.dispatch(createIncrementAction(value - 0));
};
decrement = () => {
const { value } = this.selectNumber;
store.dispatch(createDecrementAction(value - 0));
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (store.getState() % 2 !== 0) {
store.dispatch(createIncrementAction(value - 0));
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
setTimeout(() => {
store.dispatch(createIncrementAction(value - 0));
}, 500);
};
render() {
return (
<div>
<h1>当前求和为: {store.getState()}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
redux\constant.js
// 该模块用于定义action对象中type类型的值
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
redux\count_action.js
import { INCREMENT, DECREMENT } from "./constant";
// 该文件专门为count组件生成action对象
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
redux\count_reducer.js
import { INCREMENT, DECREMENT } from "./constant";
/**
* 1. 该文件是用于创建一个为 count 组件服务的 reducer, 本质就是一个函数;
* 2. reducer函数会接收两个参数,分别是:之前的状态 preState, 动作对象 action
*/
const initState = 0;
export default function countReducer(preState = initState, action) {
const { type, data } = action;
// console.log(type, data);
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
redux\store.js
// 该文件专门用于暴露一个store对象, 整个应用只有一个store;
// 引入createStore,专门用于创建store对象
import { createStore } from "redux";
// 引入为 count 组件服务的 reducer
import countReducer from "./count_reducer";
export default createStore(countReducer);
21-Redux 异步
Count.jsx
import React, { Component } from "react";
// 引入 store
import store from "../../redux/store";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
store.dispatch(createIncrementAction(value - 0));
};
decrement = () => {
const { value } = this.selectNumber;
store.dispatch(createDecrementAction(value - 0));
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (store.getState() % 2 !== 0) {
store.dispatch(createIncrementAction(value - 0));
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
store.dispatch(createIncrementAsyncAction(value - 0, 500));
};
render() {
return (
<div>
<h1>当前求和为: {store.getState()}</h1>
<select ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
redux\store.js
// 该文件专门用于暴露一个store对象, 整个应用只有一个store;
// 引入createStore,专门用于创建store对象
import { createStore, applyMiddleware } from "redux";
// 引入 redux-thunk 用于支持 异步 action
import thunk from "redux-thunk";
// 引入为 count 组件服务的 reducer
import countReducer from "./count_reducer";
export default createStore(countReducer, applyMiddleware(thunk));
redux\count_action.js
import { INCREMENT, DECREMENT } from "./constant";
// 该文件专门为count组件生成action对象
// 同步 action 也就是 action 值为对象
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
// 异步 action 也就是 action 值为函数,异步 action 不是必须要用的
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data));
}, time);
};
};
22-React-Redux 的基本使用
index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
//引入组件
import App from "./App.jsx";
import store from "./redux/store.js";
// 检测 redux 中状态的变化,变化了就重新渲染页面,重新render一下
store.subscribe(() => {
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
});
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import CountUI from "./containers/Count";
import store from "./redux/store";
export default class App extends Component {
render() {
return (
<div>
<CountUI store={store} />
</div>
);
}
}
03-React-cli\22-React-Redux 的基本使用\containers\Count\index.jsx
// 引入CountUI组件
import CountUI from "../../components/Count";
import { INCREMENT, DECREMENT } from "../../redux/constant";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
// 引入 store ,这里的 store 不能自己去引入,要去上层使用 props 传过来
// 引入 connect 用于连接 store 和 UI组件
import { connect } from "react-redux";
/**
* 1. 因为 props 取的时候得 key value 的形式,所以需要对象的形式,
* 2. 返回的对象作为对象会传给组件 - 状态
* 3. a 函数的返回值作为状态返回给了UI组件
*/
function mapStateToProps(state) {
// state 是他们传给我们,不需要自己引入
return { count: state };
}
/**
* 1. 因为 props 取的时候得 key value 的形式,所以需要对象的形式,
* 2. 返回的对象作为对象会传给组件 - 操作状态的方法
*/
function mapDispatchToProps(dispatch) {
// dispatch 也是他们传给我们的,不需要我们自己引入
return {
increment: (data) => dispatch(createIncrementAction(data)), // 通知 redux 执行加法
decrement: (data) => dispatch(createDecrementAction(data)), // 通知 redux 执行加法
incrementAsync: (data, time) =>
dispatch(createIncrementAsyncAction(data, time)), // 通知 redux 执行加法
};
}
// 使用 connect 创建并暴露一个 CountUI 的容器组件
// 传两个值
// 1. redux 中所保存的数据
// 2. 用于操作状态的方法
export default connect(mapStateToProps, mapDispatchToProps)(CountUI);
03-React-cli\22-React-Redux 的基本使用\components\Count
import React, { Component } from "react";
export default class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.increment(value - 0);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.decrement(value - 0);
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.increment(value - 0);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.incrementAsync(value - 0, 500);
};
render() {
return (
<div>
<h1>当前求和值为: {this.props.count}</h1>
<select style={{ width: "100px" }} ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
//引入组件
import App from "./App.jsx";
import store from "./redux/store.js";
// 检测 redux 中状态的变化,变化了就重新渲染页面,重新render一下
store.subscribe(() => {
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
});
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
23-react-redux 优化
03-React-cli\23-react-redux 优化\containers\Count
// 定义CountUI组件
import React, { Component } from "react";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/count_action";
// 引入 connect 用于连接 store 和 UI组件
import { connect } from "react-redux";
class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.increment(value - 0);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.decrement(value - 0);
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.increment(value - 0);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.incrementAsync(value - 0, 500);
};
render() {
return (
<div>
<h1>当前求和值为: {this.props.count}</h1>
<select style={{ width: "100px" }} ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
// 使用 connect 创建并暴露一个 CountUI 的容器组件
// 传两个值
// 1. redux 中所保存的数据
// 2. 用于操作状态的方法
export default connect(
(state) => ({ count: state }),
// mapStateToProps 一般写法
// (dispatch) => ({
// increment: (data) => dispatch(createIncrementAction(data)), // 通知 redux 执行加法
// decrement: (data) => dispatch(createDecrementAction(data)), // 通知 redux 执行加法
// incrementAsync: (data, time) =>
// dispatch(createIncrementAsyncAction(data, time)), // 通知 redux 执行加法
// })
// mapStateToProps 简易写法
{
increment: createIncrementAction,
decrement: createDecrementAction,
incrementAsync: createIncrementAsyncAction,
}
)(Count);
App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import Count from "./containers/Count";
export default class App extends Component {
render() {
return (
<div>
<Count />
</div>
);
}
}
index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
//引入组件
import App from "./App.jsx";
import store from "./redux/store.js";
import { Provider } from "react-redux";
// 检测 redux 中状态的变化,变化了就重新渲染页面,重新render一下
// 但是,用上 react-redux 之后就不需要这个了
// store.subscribe(() => {
// ReactDOM.render(
// <BrowserRouter>
// <App />
// </BrowserRouter>,
// document.getElementById("root")
// );
// });
ReactDOM.render(
// 在这里这样写的话就不需要每个组件都传 store 了
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
24-react-redux 组件间数据共享
03-React-cli\24-react-redux 组件间数据共享\containers\Count\index.jsx
// 定义CountUI组件
import React, { Component } from "react";
import {
createIncrementAction,
createDecrementAction,
createIncrementAsyncAction,
} from "../../redux/actions/count";
// 引入 connect 用于连接 store 和 UI组件
import { connect } from "react-redux";
class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.increment(value - 0);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.decrement(value - 0);
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.increment(value - 0);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.incrementAsync(value - 0, 500);
};
render() {
return (
<div>
<h4>我是 Count 组件,下方组件人数为{this.props.person.length}</h4>
<h5>当前求和值为: {this.props.count}</h5>
<select style={{ width: "100px" }} ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
// 使用 connect 创建并暴露一个 CountUI 的容器组件
// 传两个值
// 1. redux 中所保存的数据
// 2. 用于操作状态的方法
export default connect(
(state) => ({ person: state.person, count: state.count }),
// mapStateToProps 一般写法
// (dispatch) => ({
// increment: (data) => dispatch(createIncrementAction(data)), // 通知 redux 执行加法
// decrement: (data) => dispatch(createDecrementAction(data)), // 通知 redux 执行加法
// incrementAsync: (data, time) =>
// dispatch(createIncrementAsyncAction(data, time)), // 通知 redux 执行加法
// })
// mapStateToProps 简易写法
{
increment: createIncrementAction,
decrement: createDecrementAction,
incrementAsync: createIncrementAsyncAction,
}
)(Count);
03-React-cli\24-react-redux 组件间数据共享\containers\Person\index.jsx
import React, { Component } from "react";
// 引入 connect 用于连接 store 和 UI组件
import { connect } from "react-redux";
import { createAddPersonAction } from "../../redux/actions/person";
class Person extends Component {
AddPerson = () => {
const name = this.nameNode.value;
const age = this.ageNode.value;
this.props.AddPerson({ name, age });
this.nameNode.value = this.ageNode.value = "";
};
render() {
return (
<div>
<h4>我是 Person 组件,上方组件求和为{this.props.count}</h4>
<input
ref={(c) => (this.nameNode = c)}
type="text"
placeholder="输入名字"
/>
<input
ref={(c) => (this.ageNode = c)}
type="text"
placeholder="输入年龄"
/>
<button onClick={this.AddPerson}>添加</button>
<ul>
{this.props.person.map((el) => {
return (
<li key={el.id}>
名字{el.name},年龄{el.age}
</li>
);
})}
</ul>
</div>
);
}
}
export default connect(
(state) => ({ person: state.person, count: state.count }),
{
AddPerson: createAddPersonAction,
}
)(Person);
redux
actions
// 03-React-cli\24-react-redux组件间数据共享\redux\actions\count.js
import { INCREMENT, DECREMENT } from "../constant";
// 该文件专门为count组件生成action对象
// 同步 action 也就是 action 值为对象
export const createIncrementAction = (data) => ({ type: INCREMENT, data });
export const createDecrementAction = (data) => ({ type: DECREMENT, data });
// 异步 action 也就是 action 值为函数,异步 action 不是必须要用的
export const createIncrementAsyncAction = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(createIncrementAction(data));
}, time);
};
};
// 03-React-cli\24-react-redux组件间数据共享\redux\actions\person.js
import { ADD_PERSON } from "../constant";
export const createAddPersonAction = (personObj) => ({
type: ADD_PERSON,
data: personObj,
});
reducers
// 03-React-cli\24-react-redux组件间数据共享\redux\reducers\count.js
import { INCREMENT, DECREMENT } from "../constant";
/**
* 1. 该文件是用于创建一个为 count 组件服务的 reducer, 本质就是一个函数;
* 2. reducer函数会接收两个参数,分别是:之前的状态 preState, 动作对象 action
*/
const initState = 0;
export default function countReducer(preState = initState, action) {
const { type, data } = action;
// console.log(type, data);
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
// 03-React-cli\24-react-redux组件间数据共享\redux\reducers\person.js
import { ADD_PERSON } from "../constant";
// 初始化人的列表
const initState = [];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
switch (type) {
case ADD_PERSON:
return [{ ...data, id: new Date().getTime() }, ...preState];
// return initState.push({ ...data, id: new Date().getTime() });
default:
return preState;
}
}
03-React-cli\24-react-redux 组件间数据共享\redux\constant.js
// 该模块用于定义action对象中type类型的值
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
03-React-cli\24-react-redux 组件间数据共享\redux\store.js
// 该文件专门用于暴露一个store对象, 整个应用只有一个store;
// 引入createStore,专门用于创建store对象
import { createStore, applyMiddleware, combineReducers } from "redux";
// 引入 redux-thunk 用于支持 异步 action
import thunk from "redux-thunk";
// 引入为 count 组件服务的 reducer
import countReducer from "./reducers/count";
// 引入为 person 组件服务的 reducer
import personReducer from "./reducers/person";
// 合并 reducers
const allReduces = combineReducers({
count: countReducer,
person: personReducer,
});
export default createStore(allReduces, applyMiddleware(thunk));
25-react-redux 开发者工具
03-React-cli\25-react-redux 开发者工具\redux\store.js
// 该文件专门用于暴露一个store对象, 整个应用只有一个store;
// 引入createStore,专门用于创建store对象
import { createStore, applyMiddleware, combineReducers } from "redux";
// 引入 redux-thunk 用于支持 异步 action
import thunk from "redux-thunk";
// 引入为 count 组件服务的 reducer
import countReducer from "./reducers/count";
// 引入为 person 组件服务的 reducer
import personReducer from "./reducers/person";
// 引入 redux-devtools-extension
import { composeWithDevTools } from "redux-devtools-extension";
// 合并 reducers
const allReduces = combineReducers({
count: countReducer,
person: personReducer,
});
export default createStore(
allReduces,
composeWithDevTools(applyMiddleware(thunk))
);
26-react-redux 最终版
03-React-cli\26-react-redux 最终版\containers
// 03-React-cli\26-react-redux最终版\containers\Count\index.jsx
// 定义CountUI组件
import React, { Component } from "react";
import {
increment,
decrement,
incrementAsync,
} from "../../redux/actions/count";
// 引入 connect 用于连接 store 和 UI组件
import { connect } from "react-redux";
class Count extends Component {
increment = () => {
const { value } = this.selectNumber;
this.props.increment(value - 0);
};
decrement = () => {
const { value } = this.selectNumber;
this.props.decrement(value - 0);
};
incrementIfOdd = () => {
const { value } = this.selectNumber;
if (this.props.count % 2 !== 0) {
this.props.increment(value - 0);
}
};
incrementAsync = () => {
const { value } = this.selectNumber;
this.props.incrementAsync(value - 0, 500);
};
render() {
return (
<div>
<h4>我是 Count 组件,下方组件人数为{this.props.persons.length}</h4>
<h5>当前求和值为: {this.props.count}</h5>
<select style={{ width: "100px" }} ref={(c) => (this.selectNumber = c)}>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
</select>
<button onClick={this.increment}>+</button>
<button onClick={this.decrement}>-</button>
<button onClick={this.incrementIfOdd}>当前求和为奇数再加</button>
<button onClick={this.incrementAsync}>异步加</button>
</div>
);
}
}
// 使用 connect 创建并暴露一个 CountUI 的容器组件
// 传两个值
// 1. redux 中所保存的数据
// 2. 用于操作状态的方法
export default connect(
(state) => ({
persons: state.persons,
count: state.count
}),
// mapStateToProps 一般写法
// (dispatch) => ({
// increment: (data) => dispatch(createIncrementAction(data)), // 通知 redux 执行加法
// decrement: (data) => dispatch(createDecrementAction(data)), // 通知 redux 执行加法
// incrementAsync: (data, time) =>
// dispatch(createIncrementAsyncAction(data, time)), // 通知 redux 执行加法
// })
// mapStateToProps 简易写法
{
increment,
decrement,
incrementAsync,
}
)(Count);
// 03-React-cli\26-react-redux最终版\containers\Person\index.jsx
import React, { Component } from "react";
// 引入 connect 用于连接 store 和 UI组件
import { connect } from "react-redux";
import { AddPerson } from "../../redux/actions/person";
class Person extends Component {
AddPerson = () => {
const name = this.nameNode.value;
const age = this.ageNode.value;
this.props.AddPerson({ name, age });
this.nameNode.value = this.ageNode.value = "";
};
render() {
return (
<div>
<h4>我是 Person 组件,上方组件求和为{this.props.count}</h4>
<input
ref={(c) => (this.nameNode = c)}
type="text"
placeholder="输入名字"
/>
<input
ref={(c) => (this.ageNode = c)}
type="text"
placeholder="输入年龄"
/>
<button onClick={this.AddPerson}>添加</button>
<ul>
{this.props.persons.map((el) => {
return (
<li key={el.id}>
名字{el.name},年龄{el.age}
</li>
);
})}
</ul>
</div>
);
}
}
export default connect(
(state) => ({
persons: state.persons,
count: state.count,
}),
{
AddPerson,
}
)(Person);
03-React-cli\26-react-redux 最终版\redux\actions
// 03-React-cli\26-react-redux最终版\redux\actions\count.js
import { INCREMENT, DECREMENT } from "../constant";
// 该文件专门为count组件生成action对象
// 同步 action 也就是 action 值为对象
export const increment = (data) => ({ type: INCREMENT, data });
export const decrement = (data) => ({ type: DECREMENT, data });
// 异步 action 也就是 action 值为函数,异步 action 不是必须要用的
export const incrementAsync = (data, time) => {
return (dispatch) => {
setTimeout(() => {
dispatch(increment(data));
}, time);
};
};
// 03-React-cli\26-react-redux最终版\redux\actions\person.js
import { ADD_PERSON } from "../constant";
export const AddPerson = (personObj) => ({
type: ADD_PERSON,
data: personObj,
});
03-React-cli\26-react-redux 最终版\redux\reducers
// 03-React-cli\26-react-redux最终版\redux\reducers\count.js
import { INCREMENT, DECREMENT } from "../constant";
/**
* 1. 该文件是用于创建一个为 count 组件服务的 reducer, 本质就是一个函数;
* 2. reducer函数会接收两个参数,分别是:之前的状态 preState, 动作对象 action
*/
const initState = 0;
export default function countReducer(preState = initState, action) {
const { type, data } = action;
// console.log(type, data);
switch (type) {
case INCREMENT:
return preState + data;
case DECREMENT:
return preState - data;
default:
return preState;
}
}
// 03-React-cli\26-react-redux最终版\redux\reducers\count.js
import { ADD_PERSON } from "../constant";
// 初始化人的列表
const initState = [];
export default function personReducer(preState = initState, action) {
const { type, data } = action;
// 在这里return 的时候,如果返回同一个数据,那么redux是不去更新页面的
switch (type) {
case ADD_PERSON:
return [{ ...data, id: new Date().getTime() }, ...preState];
default:
return preState;
}
}
// 03-React-cli\26-react-redux最终版\redux\reducers\index.js
// 该文件用于汇总所有的 reduce
// 引入createStore,专门用于创建store对象
import { combineReducers } from "redux";
// 引入为 count 组件服务的 reducer
import count from "./count";
// 引入为 person 组件服务的 reducer
import persons from "./person";
// 合并 reducers
export default combineReducers({
count,
persons,
});
03-React-cli\26-react-redux 最终版\redux\constant.js
// 该模块用于定义action对象中type类型的值
export const INCREMENT = "increment";
export const DECREMENT = "decrement";
export const ADD_PERSON = "add_person";
03-React-cli\26-react-redux 最终版\redux\store.js
// 该文件专门用于暴露一个store对象, 整个应用只有一个store;
// 引入createStore,专门用于创建store对象
import { createStore, applyMiddleware } from "redux";
// 引入 redux-thunk 用于支持 异步 action
import thunk from "redux-thunk";
// 引入 redux-devtools-extension
import { composeWithDevTools } from "redux-devtools-extension";
// 引入所有的 reducers
import allReduces from "./reducers/index";
export default createStore(
allReduces,
composeWithDevTools(applyMiddleware(thunk))
);
03-React-cli\26-react-redux 最终版\App.jsx
//创建外壳组件APP
import React, { Component } from "react";
import Count from "./containers/Count";
import Person from "./containers/Person";
export default class App extends Component {
render() {
return (
<div>
<Count />
<hr />
<Person />
</div>
);
}
}
03-React-cli\26-react-redux 最终版\index.js
//引入核心库
import React from "react";
import ReactDOM from "react-dom";
//引入组件
import App from "./App.jsx";
import store from "./redux/store.js";
import { Provider } from "react-redux";
// 检测 redux 中状态的变化,变化了就重新渲染页面,重新render一下
// 但是,用上 react-redux 之后就不需要这个了
// store.subscribe(() => {
// ReactDOM.render(
// <BrowserRouter>
// <App />
// </BrowserRouter>,
// document.getElementById("root")
// );
// });
ReactDOM.render(
// 在这里这样写的话就不需要每个组件都传 store 了
// 此处需要 Provider 包裹一下 App,目的是为了 App 后代都可以接收到 store
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);