React
笔记来自
github实例
immutable的学习
面试题
手写实现react
需要学的知识有
- 脚手架安装启动
- JSX组件基础使用,修改数据,for,if,事件...
- JSX组件传参通信
- 生命周期
- 路由
- Redux
- React-Hooks
- 打包发布
- 首屏优化,Next服务器渲染
安装脚手架
- 普通的命令
# 一个电脑安装一次就好
cnpm install -g create-react-app
# 创建项目
create-react-app 【name】
cnpm install
npm start
- 脚手架有什么
// 自带了Ject测试插件
// eslint代码规范检查
// PWA功能的 manifest.json 和 serviceWorker.js 文件
// 入口文件 index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
// 这是一个组件
import App from './App';
// import * as serviceWorker from './serviceWorker';
// 这个就是jsx写法
// 后面等引入了路由和redux后得修改,具体往下看
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
// PWA没用注释了
// serviceWorker.unregister();
脚手架设置
- 跨域请求
// 安装
npm i http-proxy-middleware --save
// 在src下创建setupProxy.js,名字固定
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app) {
app.use('/api',
createProxyMiddleware({
target: 'http://xxx.pdt1997.top/',
changeOrigin: true
})
);
}
// axios安装设置查看【axios和fetch】笔记
- 打包文件的配置查看【React打包配置】笔记
基础使用
- 组件的结构
// vue是一个template+script+style组成的
// 而react是一个js文件加一个css文件,建议创建一个文件夹装起来使用,再一起装进pages文件夹里比较规范
// app.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
// 上面的写法不规范,应该改成下面的写法
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
// 这里面的一级属性都不需要逗号结束
class App extends Component{
// 这个就是vue的data
state = {
msg: "测试",
}
render(){
return (
<div className="App">
<header className="App-header">
<div>{this.state.msg}</div>
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
}
export default App;
- 修改数据,在react应该叫修改状态state
// 不要直接修改 state(状态)
// this.state.comment = 'Hello';
// 上述代码并不会重新渲染组件,需要使用this.setState()代替:
// 正确操作
this.setState({
comment: 'Hello'
});
// state(状态) 更新可能是异步的
// React 为了优化性能,有可能会将多个 setState() 调用合并为一次更新。
// 因为this.props和this.state 可能是异步更新的,你不能依赖他们的值计算下一个state(状态)
// this.setState({
// counter: this.state.counter + this.props.increment,
// });
// 我们并不能通过上述代码得到想要的值
// 为了弥补这个问题,使用另一种 setState() 的形式,接受一个函数
// 这个函数将接收前一个状态作为第一个参数,应用更新时的 props 作为第二个参数,代码如下:
this.setState((prevState, props) => ({
counter: prevState.counter + props.increment
}));
- 事件绑定
class Toggle extends React.Component {
state = {
isToggleOn: true,
}
// 一定要箭头函数,否则没有this
handleClick = (e) => {
// 这就是修改state方法
this.setState({
isToggleOn: !this.state.isToggleOn
});
}
// event永远在最后一位参数
handleClick2 = (msg,e) => {
console.log(msg)
}
render() {
return (
<button onClick={this.handleClick('test')}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
// 如果要传参就得加上bind(this,参数)
<button onClick={this.handleClick2.bind(this,'test')}>
{this.state.isToggleOn ? 'ON' : 'OFF'}
</button>
);
}
}
- 条件渲染
// 三元
render() {
return (
<div>
{ this.state.isLoggedIn ? (
<LogoutButton onClick={this.handleLogoutClick} />
) : (
<LoginButton onClick={this.handleLoginClick} />
) }
</div>
);
}
// 是否 &&
render() {
return (
<div>
<h1>Hello!</h1>
{ unreadMessages.length > 0 &&
<h2>
您有 {unreadMessages.length} 条未读信息。
</h2>
}
</div>
);
}
- 列表渲染
render() {
return (
<div>
{
this.state.selectedProList.map((item, index) => {
return <li key={index} className="selected-pro-item ellipsis">{item.product_name}x{item.selectNum}</li>
})
}
</div>
);
}
JSX组件传参通信
- 所有的数据和方法都在
this.props
对象里 - 父传子
// 父
render(){
return(
<Child {...person} />
<Child txt={this.state.message}/>
)
}
// 子
render(){
return(
<div>{this.props.name}</div>
<div>{this.props.age}</div>
<div>{this.props.message}</div>
)
}
- 子传父,子组件调用父组件的方法进行数据的传递
// 父
getDatas(msg){
//把子组件传递过来的值赋给this.state中的属性
this.setState({
mess: msg
});
}
render(){
return (
<Son getdata={this.getDatas.bind(this)}></Son>
<div>展示数据:{this.state.mess}</div>
);
}
// 子
handleClick(){
//通过props属性获取父组件的getdata方法,并将this.state值传递过去
this.props.getdata(this.state.inputValue);
}
render(){
return (
<button onClick={this.handleClick.bind(this)}>点击获取数据</button>
);
}
- 兄弟,组件A传值父组件,父组件传值组件B,就是把上面的
// 父
getDatas(msg){
//把子组件传递过来的值赋给this.state中的属性
this.setState({
mess: msg
});
}
render(){
return (
<SonA getdata={this.getDatas.bind(this)} />
<SonB mess={mess} />
);
}
- 组件传值可以使用
prop-type
这个插件进行格式判断和默认值使用 - 跟vue一样,数据之间的传递非常的麻烦,应该是用第三方的数据储存插件
redux
生命周期
- 核心 constructor 》componentWillMount 》render 》componentDidMount
class Button extends Component {
state = {
data: 0
}
setNewNumber() {
this.setState({data: this.state.data + 1})
}
render() {
return (
<div>
<button onClick = {this.setNewNumber.bind(this)}>INCREMENT</button>
<Content myNumber = {this.state.data}></Content>
</div>
);
}
}
class Content extends Component {
componentWillMount() {
// 在渲染前调用,在客户端也在服务端
console.log('Component WILL MOUNT!')
}
componentDidMount() {
// 在第一次渲染后调用,只在客户端
// 初始化请求写在这
// 为什么不写在componentWillMount
// 因为componentWillMount方法的调用在constructor之后,在render之前,在这方法里的代码调用setState方法不会触发重渲染,所以它一般不会用来作加载数据之用,它也很少被使用到
console.log('Component DID MOUNT!')
}
componentWillReceiveProps(newProps) {
console.log('Component WILL RECEIVE PROPS!')
}
shouldComponentUpdate(newProps, newState) {
// 这个是数据更新前会执行的方法,如果返回false,页面不会更新
// 这个的用处特别的大,如果你在render里打印一下666,会发现每次数据更新实际都调用了无数次的render,非常的损耗性能
// 当然必须要的不能阻止,如果是前后一样的数据应该避免render的更新,所以在这里可以对两个参数进行一致性判断,一样则返回false
// 可是这个数据的判断就是深拷贝,深拷贝的性能也是非常的离谱,也不好完成
// 所以在这里应该使用插件,也就是最上的那个immutable插件
// 引用这个插件后,整个项目的数据都应该改用插件里使用的【List和Map和Set和其他】,按照他要求的方法进行数据变化
// 具体自行学习
return true;
}
componentWillUpdate(nextProps, nextState) {
console.log('Component WILL UPDATE!');
}
componentDidUpdate(prevProps, prevState) {
// 数据更新调用
console.log('Component DID UPDATE!')
}
componentWillUnmount() {
// 销毁前
console.log('Component WILL UNMOUNT!')
}
render() {
return (
<div>
<h3>{this.props.myNumber}</h3>
</div>
);
}
}