Привет~ Я Том, это маршрут обучения React, который я организовал, и аналогия Vue во многих местах в статье, я надеюсь, что вы уже знакомы с Vue.js до прочтения.
Это будет самое полное руководство React по Nuggets, которое включает инструменты React.js, Redux, маршрутизации и cli. Руководство в основном основано на этапах использования и рассказывает, как напрямую реализовать требования. Это руководство в основном предназначено для начинающих. , Реагируйте студентов, поэтому я буду игнорировать некоторые ненужные шаги или ненужные инструкции, чтобы предотвратить путаницу и снизить эффективность обучения.
Давайте начнем!
Установить
Как и Vue, React сначала развивается и учится благодаря введению тегов.
-
импортировать три файла
<!-- babel,用于编译JSX语法 --> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <!-- react --> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <!-- react-dom --> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
-
Создайте тег скрипта
//script标签的type要为text/babel,因为这里需要babel来解析JSX语法 <script type="text/babel"> function MyFirstComponent(props){ return( <h1>我是tom,这是我创建的第一个react组件</h1> ) } //调用ReactDOM.render方法,渲染组件 ReactDOM.render(<MyFirstComponent/>,document.getElementById('root')) </script>
-
Создайте тег html, который отображает компонент реакции
<div id="root"></div>
-
Просто запустите его, вставьте полный HTML-код, написанный в соответствии с приведенными выше шагами ниже.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>StudyReact</title> </head> <body> <div id="root"></div> <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script> <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> <script type="text/babel"> function MyFirstComponent(props){ return( <h1>我是tom,这是我创建的第一个react组件</h1> ) } //调用 ReactDOM.render 方法 ReactDOM.render(<MyFirstComponent/>,document.getElementById('root')) </script> </body> </html>
Синтаксис JSX
Он немного отличается от единственного файла vue.vue. Синтаксис jsx интегрирует только структуру (html) и поведение (js) компонента, но не интегрирует производительность (css). CSS все еще находится в форме введения .
-
Вы можете написать синтаксис HTML напрямую:
-
let ele_obj = <div>hello world</div> //这里比较离谱的事情是,这里的结构代码不需要加''引号 //以前我们常用的的做法是将html结构写成字符串的形式,再使用dom对象的innerHTML进行解析。
-
-
Выражения интерполяции JSX используют одинарные фигурные скобки, что отличается от использования vue двойных фигурных скобок усов.
-
let name_str = 'ahreal' let ele_obj = <div>my name is <span>{name_str}</span> </div>
-
-
При использовании одного тега необходимо добавить /
-
let ele_obj = <img src="..." />
-
-
Используйте класс для использования className
-
let ele_obj = <p className="name">ahreal</p>
-
-
Используйте стиль встроенного стиля для вставки непосредственно в качестве объекта
-
let ele_obj = <div style={{'color':'red','fontSize':'20px'}}>hello,world!</div> //1.这里插入的是以对象的形式进行插入,所以这里用了双大括号,第一个括号是插值语法,第二个括号是对象的括号 //2.写样式的时候,如果遇到连接符号font-size这类应该改成驼峰形式fontSize //3.中间使用逗号,隔开 ,注意区分html里面是用分号;隔开 //4.强调外层不要有''引号这些东西,直接两个大括号{{}}
-
Как определяются компоненты
Первая буква имени компонента должна быть заглавной
Определяется функцией
function person(props){
return <div>hello,{props.name}</div> {/* 函数定义组件返回的必须是一个jsx对象 */}
}
Определяется классом
Если вы определяете компонент по классу, то компонент должен наследоваться от класса React.Component.
class person extends React.Component{
//必须定义一个render方法,
render(){
{/* 也是必须返回一个jsx对象 */}
return <h1>hello,{this.props.name}</h1>
}
//也可以定义组件的类的方法
sayName(){
console.log('我的名字是'+this.props.name)
}
}
В определении класса не нужно писать реквизиты формальных параметров, потому что реквизиты наследуются от React.Component, и для доступа требуется только this.props.
привязка событий
-
Привязать непосредственно к визуализируемому тегу объекта jsx, который нужно записать в виде верблюжьего регистра
Например: onclick записывается как onClick
-
Функция обработки событий написана непосредственно как метод класса
-
Если вам нужно получить доступ к этому (самому компоненту) внутри функции обработки событий, прямой доступ не определен.
решение:
-
Используйте привязку, чтобы указать этот указатель при привязке обработчиков событий.
class MyCom extends React.Component{ render(){ //这里在调用的时候使用bind return <div onClick={this.handleClick.bind(this)}>这是一个自定义组件</div> } handleClick(){ console.log('我被点击了'+this.props.message) } } ReactDOM.render(<MyCom message="ahreal"/>,document.getElementById('root'))
-
Используйте стрелочные функции
class MyCom extends React.Component{ render(){ return <div onClick={this.handleClick}>这是一个自定义组件</div> } //使用箭头函数去定义事件回调 handleClick=()=>{ console.log('我被点击了'+this.props.message) } }
-
-
пропуск на мероприятие
-
Использовать привязку для передачи параметров (нельзя передавать параметры напрямую, иначе вызовется сразу)
onClick = {this.handleClick.bind(this,arg1,arg2...)}
-
Если вы не используете привязку, вам нужно обернуть еще один слой стрелочных функций.
onClick = { ()=>{this.handleClick(arg1,arg2)} }
-
будь осторожен:
- Поведение по умолчанию не может быть предотвращено обработчиком событий, возвращающим false, необходимо использовать e.preventDefault().
состояние компонента
создать состояние
Если вам нужно определить пользовательские свойства компонента, вconstructorОпределить состояние в конструкторе
class Mycom extends React.Component {
constructor(props){
super(props)
//给this.state赋值一个对象,对象的属性就是组件的自定义属性
this.state = {
iNum:10
}
}
}
изменить состояние
Вы не можете напрямую изменить значение состояния, иначе данные не могут управлять ассоциацией, вам нужно использоватьsetState
Метод setState получает параметр, который является объектом, аналогичным родному setData апплета.
Метод setState является асинхронным методом.
this.setState({
iNum:12
})
Метод setState также может получать параметры как функцию,Первый параметр функции - это состояние,Второй параметр реквизит
this.setState(function(state,props){
return {iNum:state.iNum+1}
})
//可用箭头函数简写成
this.setState(state=>({iNum:state.iNum+1}))
//补充一下箭头函数
function(state){
return {iNum:state.iNum+1}
}
//先去掉function关键字,加上go's to =>
(state)=>{
return {iNum:state.iNum+1}
}
//因为只有一个参数,接收参数的()可以省略
state=>{
return {iNum:state.iNum+1}
}
//因为函数内部直接是返回值,所以函数体可以省略return 并且省略{}
state=>{iNum:state.iNum+1}
//因为返回值是一个对象,对象本身的{}会被理解成函数体的{},所以需要再包一层()
state=> ({iNum:state.iNum+1})
При использовании формы функции для передачи параметров это может решить некоторые неприятные проблемы, вызванные асинхронностью.
Уведомление:
setState не зависит от таких значений, как this.state или this.propsПоскольку изменение будет реагировать на большее количество состояний и реквизитов, чтобы идти со значением комбинированного выполнения для повышения производительности, поэтому, если у нас есть зависимость от setState внутри, это принесет ряд неприятностей.
Мы используем setState для передачи функции.Функция имеет два параметра, state и props по умолчанию.Если вы используете эти два параметра для доступа, проблем не будет.
Кроме того, setState также может получать второй параметр, второй параметр — это функция обратного вызова.
После приведенного выше вступления все знают, что установка значения setState — это асинхронная операция, и если нам нужно выполнить какие-то логические операции после установки состояния, мы можем передать второй параметр в виде обратного вызова в setState.
Как показано ниже.
this.setState({
name:'ahreal'
},()=>{
console.log('state值修改成功,现在的name值为'+this.state.name)
})
Концепция: компоненты с состоянием и без состояния
- Определите, является ли это компонентом с состоянием, по тому, есть ли состояние или нет
- Компоненты, определенные функцией, являются компонентами без состояния, компоненты, определенные классом, могут быть компонентами с состоянием или компонентами без состояния.
Рендеринг списка
В React рендеринг списка использует метод карты массива, а рендеринг списка должен использовать ключ
let myArr = ['jack','allen','ahreal']
class MyCom extends React.Component{
render(){
return (
<ul>
{
myArr.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
)
}
}
условный рендеринг
Два способа условного рендеринга
-
использоватьif-else
-
Вернуть объект jsx напрямую
class LoginState extends React.Component{ render(){ { if(this.props.isLogin){ return <p>已经登录</p> }else{ return <p>未登录</p> } } } }
-
возвращать разные дочерние компоненты
function Login(){ return <p>已经登录</p> } function Loginout(){ return <p>未登录</p> } class LoginState extends React.Component{ render(){ { if(this.props.isLogin){ return <Login></Login> }else{ return <Loginout></Loginout> } } } }
-
-
использовать&&
class Notice extends React.Component{
render(){
let {username,message} = this.props
{
return (
<div>
<p>欢迎您,{username}</p>
{message.length&&<p>您有{message.length}条信息</p>}
</div>
)
}
}
}
Если вам нужно более четкое различие между поведением и структурой, вы можете использовать переменные для хранения объектов jsx.
Например:
function Login(){
return (
<button>登录</button>
)
}
function LoginOut(){
return(
<button>注销</button>
)
}
class LoginButton extends React.Component {
render(){
let isLogin = false
let btn
if(isLogin){
btn = <LoginOut></LoginOut>
}else{
btn = <Login></Login>
}
return (
<div>
<h1>登录状态</h1>
<btn></btn>
</div>
)
}
}
Если вы хотите предотвратить рендеринг всего компонента, вы можете вернуть null
двусторонняя привязка
React не помогает нам инкапсулировать V-модель, похожую на vue.
Поэтому нам нужно самим инкапсулировать двустороннюю привязку.
Компоненты формы React, которые связывают данные состояния, называются контролируемыми компонентами.
Простые шаги реализации:
-
инициализировать данные по умолчанию
constructor(props){ super(props) this.state = { //初始化了一个message,message作为双向绑定的数据媒介 message:this.props.message } }
-
Привязать сообщение к выводу
render(){ return ( <div> <p>{this.state.message}</p> </div>) }
-
Привяжите сообщение к вводу и привяжите событие изменения
render(){ return ( <div> <p>{this.state.message}</p> <input value={this.state.message} onChange={this.changeMessage.bind(this)}/> </div>) }
-
Объявите метод changeMessage для динамического изменения состояния.
changeMessage(e){ let newValue = e.currentTarget.value this.setState(()=>({message:newValue})) }
Использование ссылки
Как и vue, React может использовать ref, чтобы пометить объект dom, а затем работать с ним.
Шаги для использования:
-
Создайте объект ref в конструкторе конструктора
constructor(props){ super(props) this.myRef = React.createRef() }
-
Отметить дом ссылкой в рендере
render(){ return( <input ref={this.myRef}/> ) }
Так что можно сказать, что нужный нам dom помечен ref
Когда нам нужно его использовать, мы можем передать
this.myRef.current
Итак, чтобы получить дом, отмеченный соответствующим ref
Концепция: контролируемые и неконтролируемые компоненты
-
Управляемые компоненты
Данные компонента связаны с состоянием, называемым контролируемым компонентом.
-
неконтролируемые компоненты
Компонент, данные которого не связаны с состоянием, называется неуправляемым компонентом.
Жизненный цикл
значок
Ссылка на официальную документацию по жизненному циклу
текстовое описание
constructor
Конструктор, который выполняется при инициализации компонента
render
Этот метод будет выполняться после метода componentWillMount, а также будет выполняться при изменении данных состояния и реквизита, поэтому этот метод будет выполняться в начале компонента и также будет выполняться в середине компонента.
componentDidMount
Метод выполняется после монтирования компонента на страницу
componentDidUpdate
Выполняется после обновления компонента
componentWillUnmount
Выполняется перед уничтожением компонента
shouldComponentUpdate
Этот метод, выполняемый перед обновлением компонента, может определить, обновлен ли компонент, и вернуть истинное обновление, ложное, а не обновление.
Если он возвращает true, компонент войдет в componentWillUpdate, затем войдет в метод рендеринга, а затем войдет в метод componentDidUpdate.
My-React-Cli
Давайте сделаем простые реагирующие леса своими руками~
основной процесс
-
Инициализировать папку проекта
npm init -y
-
Скачать реакцию и реакцию-дом
npm i react react-dom -S
-
Скачайте webpack и webpack-cli
npm i webpack webpack-cli -D
-
Загрузите загрузчик Babel и ядро Babel
npm i babel-loader @babel/core -D
-
Загрузите пресет реакции Babel
npm i @babel/preset-react -D
-
Создайте файл webpack.config.js для настройки загрузчика.
module:{ rules:[ { test:/\.js$/, //匹配到node_modules文件夹下面的就跳过loader的处理 exclude:/node_modules/, //使用的loader loader:'babel-loader', } ] }
-
Создайте файл конфигурации babel .babelrc в корневом каталоге и настройте реакцию babel-preset
{ "presets":[ "@babel/preset-react" ] }
Пока построен простой скаффолдинг реакта.Конечно он реализует только базовую компиляцию реактивных js файлов.Конечно в общем нужно настроить css-loader,file-loader,dev-server и т.д. , потому что они не лежат в основе React scaffolding внутри, поэтому я не буду вдаваться в подробности.
Router
веб-разработка использует react-router-dom
Разница между react-router-dom и react-router:router-dom является дополнением к router, добавляет такие компоненты, как borswerRouter, Link и т. д. После установки react-router-dom устанавливать react-router не нужно.
Установить
-
под пакетом
npm i react-router-dom -S
-
пакет гида
import {HashRouter,Link,Route,Switch,Redirect} from 'react-router-dom'
в:
- HashRouter определяет общий контейнерный компонент хеш-маршрутизации.
- Связать одиночную метку, определить ссылку маршрута и определить адрес ссылки через атрибут to
- Одна метка маршрута, которая определяет метку контейнера компонента, определяет адрес, соответствующий атрибуту to ссылки через путь, а атрибут компонента определяет компонент, соответствующий ссылке.
- Переключите метки контейнера за пределы нескольких меток маршрута. Если вам нужно определить переходы 404 и переходы с перенаправлением, вам нужно обернуть метку маршрута этой меткой.
- Перенаправление определяет перенаправление маршрута, определяет исходный маршрут через атрибут from и определяет маршрут перенаправления через атрибут to.
Основное использование
Маршрут реакции можно импортировать прямо на страницу, где нужно написать router-view.
import {HashRouter,Route,Link} from 'react-router-dom'
class MyRouter extends React.Component {
render(){
return(
//HashRouter包裹在最外层作为路由组件的根组件
<HashRouter>
//Link组件就是一个a标签,to定义链接的地址
<Link to="/">router1</Link>
<Link to="/router2">router2</Link>
<Link to="/router3">router3</Link>
<hr/>
//Route就是一个表明链接对应的组件,同时表示路由组件渲染的位置,exact字段表示精准匹配
<Route path="/" exact component={router1}></Route>
<Route path="/router2" component={router2}></Route>
<Route path="/router3" component={router3}></Route>
</HashRouter>
)
}
}
точно указывает, что маршрут является точным совпадением, а маршрут реакции по умолчанию — нечетким совпадением.
404 страница
два шага
-
Напишите тег маршрута в конце без атрибута пути, указывающий, что любой путь может быть сопоставлен.
<Route path="/" exact component={router1}></Route> <Route path="/router2" component={router2}></Route> <Route path="/router3" component={router3}></Route> <Route component={Page404}></Route>
-
Слой компонентов коммутатора обернут снаружи, что означает сопоставление сверху вниз, и может сопоставляться только один маршрут.
<Switch> <Route path="/" exact component={router1}></Route> <Route path="/router2" component={router2}></Route> <Route path="/router3" component={router3}></Route> <Route component={Page404}></Route> </Switch>
Компонент перенаправления перенаправления
Получает от и до
<Redirect from="/" to="/page1"></Redirect>
вложение маршрута
Вы можете напрямую написать подкомпонент маршрутизации в маршрутизации.Когда маршрутизация вложена в маршрутизацию, самому внешнему уровню не нужно упаковывать HashRouter.
Значение передачи динамической маршрутизации и значение получения
Как и при динамической маршрутизации Vue-router, используйте **: двоеточие** при определении пути маршрутизации.
шаг:
-
Реализует объявление параметров на пути маршрута, аналогично формальным параметрам функции.
import { BrowserRouter as Router, Switch, Route, useParams } from "react-router-dom"; function MyComponent(props){ return ( <Router> <Switch> //这里跳转的形参 <Route path="/:id" component={<Child/>}></Route> </Switch> </Router> ) }
-
При переходе напишите значение в соответствующей позиции URL
import { BrowserRouter as Router, Switch, Route, useParams } from "react-router-dom"; function MyComponent(props){ return ( <Router> //跳转的url直接在对应位置写参数 <Link to="/ahreal">点我传递ahreal</Link> <Link to="/allen">点我传递allen</Link> <Switch> //这里跳转的形参 <Route path="/:name" component={<Child/>}></Route> </Switch> </Router> ) }
-
Получить параметры через useParasm в соответствующем компоненте
import { BrowserRouter as Router, Switch, Route, useParams } from "react-router-dom"; function Child(props){ //对应组件里面使用useParams取参数 let {name} = useParams return ( <div>传递过来的参数是:{name}</div> ) }
Программная навигация
В первую очередь необходимо знать, что компоненты делятся на маршрутизирующие компоненты и немаршрутизирующие компоненты.
- Компоненты маршрутизации, упакованные в Router и отображаемые после сопоставления, называются компонентами маршрутизации.
- Компоненты не маршрутизации не совпадают и отображаются маршрутизатором.
разница
- Компоненты маршрутизации могут получать историю непосредственно из this.props.history.
- Немаршрутизирующие компоненты не могут получить историю напрямую, они должны взаимодействовать с withRouter.
Этапы реализации
-
Компонент маршрутизации:
//组件方法内部直接获取history jump(){ this.props.history.push(url) }
-
Компоненты без маршрутизации:
//引入withRouter import { withRouter } from 'react-router-dom' //正常定义组件 class tabBar extends React.Component{ render(){ return ( <ul> <li onClick={this.handleClick.bind(this,'/home')}>首页</li> <li onClick={this.handleClick.bind(this,'/cate')}>分类</li> <li onClick={this.handleClick.bind(this,'/home')}>个人中心</li> </ul> ) } handleClick(url){ //如路由组件一样直接使用this.props.history this.props.history.push(url) } } //暴露的时候需要使用装饰者设计模式使用withRouter包裹一下组件,注意,一定要是最外层 export default withRouter(tabBar)
Пользовательские маршруты (Route Guards)
Выше мы упомянули, что компонент Route может получить компонент Component, и когда путь совпадет, компонент Route будет отрендерен. Мы также можем сделать что-то после сопоставления пути, что похоже на защиту маршрута в Vue.
Компонент Route по-прежнему используется, но на этот раз компонент не передает данные через Component.renderАтрибуты.
import {Route} from 'react-router-dom'
function Custom(){
return (
<Route path="/index" Render={()=>{
//isLogin判断用户是否登录,如果登录了渲染首页,没有登录渲染登录
if(isLogin){
return <Index></Index>
}else{
return <Login></Login>
}
}}/>
)
}
Существует также распространенная ситуация с использованиемchildrenАтрибуты, которые помогут нам сделать соответствующий рендеринг
сопоставление рендеринга
Предположим, у нас есть требование, мы хотим сделать кнопку, когда она находится на главной странице, кнопка «Домой» выделена
import {Route} from 'react-router-dom'
function Custom(){
return (
//match为一个布尔值,由Route默认传入,告知匹配结果。
<Route path="/index" children={({match})=>{
return(
//当匹配成功的时候,添加类名active高亮,否则移除active
<Button className={ match ?'active':'' }>首页</Button>
)
}}></Route>
)
}
передать по значению
между отцом и сыном
-
отец сыну
Когда родительский компонент ссылается на дочерний компонент, он напрямую передается в виде встроенных свойств, а дочерний компонент получает переданное значение через имя свойства this.props.
Обратите внимание, что, как и Vue, он имеет концепцию одностороннего потока данных, и невозможно напрямую изменить свойства реквизита, переданные родительским компонентом.
-
сын к отцу
Родительский компонент объявляет в себе метод получения данных и передает этот метод дочернему компоненту в виде встроенного атрибута, дочерний компонент получает вызов этого метода и передает значение в виде параметров метода.
Между братьями (режим автобуса)
- Используйте класс EventEmitter во внутренних событиях модуля реагирования для создания экземпляра объекта шины, передачи значений через режим публикации-подписки, запуска пользовательских событий в компоненте через bus.emit, а компонент, получающий данные, прослушивает события через bus.on .
Redux
Единое управление состоянием в реакции
Основной процесс
** Компонент React: ** Компонент React является пользователем избыточности, получает значение избыточности или изменяет значение избыточности.
** Хранилище: ** Объект хранилища, хранилище данных, компоненты должны получать или изменять данные через объект хранилища.
**Редукторы: **Отвечают за операции с данными, определяют операцию, соответствующую типу действия, и определяют начальное значение хранилища данных по умолчанию.
** Создатели действий: ** Действие по манипулированию данными, аналогичное рабочему заданию, если компоненту необходимо изменить данные избыточности, ему необходимо создать действие, действие объявляет тип и значение и передает его в хранилище для манипулировать данными
Установить и развернуть избыточность
-
под пакетом
npm install redux -S
-
Создать папку магазина
-
Создать index.js
import {createStore} from 'redux' import reducer from './reducer.js' let store = createStore(reducer) export default store
-
Создать редуктор.js
let defaultData = { } function reducer(state=defaultData,action){ return state } export default reducer
руководство
**Значение: **Компонент вводит объект хранилища и вызывает метод getState объекта хранилища для получения текущего хранилища данных.
let storeData = store.getData()
**Изменить значение: **Заранее объявить метод обработки, соответствующий соответствующему типу действия, в файле редуктора. Компонент создает объект рабочего задания «Действие» и вызывает метод отправки объекта хранилища для его обработки. Если нам нужно отслеживать изменение значения, нам нужно вызвать подписку и передать обратный вызов
-
Объявить метод обработки в файле редуктора
let reducer = (state=defaultData,action)=>{ if(action.type==='addNum'){ //深拷贝一个state,在拷贝的state上面对值进行操作 let newState = JSON.parse(JSON.stringify(state)) newState.Num += action.value //最后要返回这个新的state return newState } return state } export default reducer
-
Создайте заказ на работу в компоненте компонента и назначьте его магазину для обработки
import store from '...' addNum(){ //创建一个action工单 let action = { type:'addNum', value:10 } //调用store的dispatch方法提交工单 store.dispatch(action) }
-
Как правило, метод подписки магазина вызывается в конструкторе для отслеживания изменений в магазине.
import store from '...' constructor(props){ super(props) //订阅redux的数据变化,当数据变化的时候会执行传递的回调 store.subscribe(this.handleStoreChange.bind(this)) } handleStoreChange(){ //一旦被执行了,就意味着redux数据变化了,需要重新获取一下 let storeData = store.getState() ... }
ПОДПИСАТЬСЯ И ОТПИСАТЬСЯ
**Подписаться: store.subscribe(fn): **Подписаться на сохранение изменений данных, при изменении данных хранилища входящий обратный вызов выполняется автоматически.
**Отменить подписку:** при вызове store.subscribe для подписки на изменения в данных магазина будет возвращен метод отмены подписки. Нам нужно только сохранить этот метод и вызывать его, когда нам нужно отказаться от подписки.
**Операция отписки должна быть выполнена до уничтожения компонента, **Поскольку переключение компонентов роутинга в React — это процесс непрерывного построения и уничтожения компонентов, если в это время нет отписки, каждый раз при переключении компонента туда и обратно, это будет Создать компонент один раз, выполнить метод конструктора один раз, и вы подпишетесь один раз (мы обычно помещаем вызов метода store.subscribe в конструктор), ** Если вы подписываетесь повторно, это вызовет утечки памяти, и ** в конечном итоге приведет к переполнению памяти
Обычные операции подписки и отписки
import store from '...'
class Mycomponent extends React.Component {
constructor(porps){
super(props)
//调用store.subscribe订阅数据变化,同时将返回的退订方法保存在this上
this.unSubscribe = store.subscribe(handleChange)
}
...
componentWillUnmount(){
//调用一下退订的方法
this.unSubscribe()
}
}
React-Redux
Первое, что вам нужно понять, это то, что redux не предназначен для реакции, его работа вообще не требует реакции, Redux можно использовать так же, как и другие сторонние фреймворки.
react-redux — это расширение redux, которое может повысить производительность redux в реакции и сделать код более элегантным.
react-redux зависит от react и redux, поэтому перед использованием react-redux он основан на вашей реакции и redux.
Установка и использование
Сначала вы должны сначала завершить установку REDUX и развернуть Store и Reducer, см. Установка развертывания Redux в примечании.
-
скачать реакцию-редукс
npm install react-redux -S
-
Используйте контекстную функцию реакции, чтобы внедрить хранилище в main.js
import store from './store/store.js' //导入react-redux的Provider import {Provider} from 'react-redux' //注入store ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
-
Импорт подключения в компоненте
import { connect } from 'react-redux'
-
Объявите два свойства и методы, которые внедряют свойства
//这里的参数state是个默认参数,这里的state指的是store的state,而不是组件自身的state let mapStateToProps = state=>{ return{ //写属性 } } let mapDispatchToProps = dispatch=>{ return{ //写方法 } }
-
Используйте подключение для декорирования компонентов и экспорта компонентов.
//connect接收两个参数,是上面定义的两个方法,connect返回一个方法,方法接收组件本身作为参数 export default connect(mapStateToProps,mapDispatchToProps)(MyComponent)
Отличия и преимущества от простого использования redux
- Нет необходимости импортировать хранилище в файл компонента
- Нет необходимости вызывать подписку для отслеживания изменений данных, автоматически отслеживать
- Если компонент является компонентом без состояния (без собственного состояния), то компонент может быть напрямую изменен для использования объявления функции (ранее использовалось только сокращение, потому что состояние сокращения необходимо получить в конструкторе компонента, поэтому он может только быть определены в виде компонентов класса), вместо этого используйте компоненты объявления функций, которые могут повысить производительность.
- Причина та же, что и выше, что делает код более лаконичным и элегантным.
Инструменты разработчика Chrome для реагирования и сокращения
Это то же самое, что и vue dev-tools, но я буду вдаваться в подробности.
Ссылка на скачивание:disk.baidu.com/is/1IQ-J3U-2…Код извлечения: f7dg
Процесс установки:
- На сетевом диске есть две папки, а именно инструменты разработчика react и инструменты разработчика redux, скачать.
- После завершения загрузки откройте меню хрома, дополнительные инструменты, расширения.
- В правом верхнем углу есть еще один режим разработчика, включите его.
- После открытия режима разработчика выберите левый верхний угол, чтобы загрузить разархивированное расширение, и выберите две только что загруженные папки.
Обратите внимание, что инструменты разработчика redux не являются стандартными, вам нужно добавить предложение в код при создании магазина.
//原本只传递一个参数reducer,现在多传递一个参数,复制过去即可。
let store = createStore(reducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
слот
Чиновники не называют его слотом, чиновники называют егокомбинация.
Я думаю, что он очень близок к концепции эффектов и слотов во Vue, и описание слотов является более ярким для описания этого пункта знаний.
Применение
Реагируйте реквизиты могут пройти объект JSX, {this.proops.xx} jsx для использования объектов, передаваемых во внешнем слое
//定义一个我们即将传递进来的子组件
function hello(props){
return <h1>Hello world</h1>
}
//定义一个props接受子组件的组件
class MyComponent extends React.Component{
render(){
return(
<div>
<h1>你好世界</h1>
{this.props.children}
</div>
)
}
}
//使用props将子组件传递进去
ReactDOM.render(<MyComponent children={<hello/>} />, document.getElementById('root'));
Побочные эффекты операции React: концепции
Извлечение данных, настройка подписок и ручное изменение DOM в компонентах React — все это побочные эффекты.
Вообще говоря, побочный эффект функции означает, что некоторые операции, которые не имеют ничего общего с возвращаемым значением параметра, выполняются внутри тела функции, такие как доступ к глобальным переменным, изменение глобальных переменных и т. д. Некоторые операции, которые не имеют ничего общего с возвращаемым значением параметра, выполняются внутри тела функции. делать с этой функцией, называются побочными эффектами функции.
Hook
Hook — это новая функция React 16.8, которая может использовать состояние и другие функции реакции при использовании функции для определения компонентов.
Хук — это постепенная стратегия, а это означает, что даже если в вашем проекте раньше не использовался хук, вы можете использовать или не использовать хук,
Хуки нельзя использовать в компонентах класса.
useState
Это хук, который поможет вам определить состояние в функциональных компонентах.
так:
Это шагомер, считать атрибут состояния ++ каждый раз, когда нажимается кнопка
//导入React使用默认导入,useState使用的是具名导入,这个和react封装的暴露策略有关。
import React,{ useState } from 'react'
function Example() {
// useState本身是一个方法,方法接收一个参数,方法返回一个数组,使用解构赋值的形式接收并且声明。
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Поговорим об этом подробноuseState
useState сам по себе является методом, метод получает параметр,Этот параметр используется в качестве начального значения состояния, которое мы хотим определить..
Например мы:
//这里是es6的解构赋值特性
const [count, setCount] = useState(0);
Эквивалентно вам в компоненте класса:
constructor(props){
super(props)
this.state:{
count:0
}
}
Так что же это за setCount? setCount — это метод, используемый для изменения состояния счетчика.
Например делаем так:
setCount(20)
Эквивалентно вам в компоненте класса:
this.setState({
count:20
})
Разница между setCount, который мы используем, и setState, поставляемым с React, заключается в том, что setState — это объединенное состояние, а setCount — замещающее значение, ведь setCount обслуживает только одно состояние.
Нетрудно установить начальное значение состояния и вызвать метод для изменения состояния.
Конечно, если у вас есть несколько состояний, вы можете просто вызывать useState несколько раз.
useEffect
Хук useEffect позволяет вашим функциональным компонентам иметь возможности жизненного цикла! Можно использовать componentDidMount, componentDidUpdate, componentWillUnmount эти три функции жизненного цикла.
Самое основное использованиеЭффект
На основе шагомера в предыдущем примере мы привязываем Count к заголовку браузера.
import React,{ useState,useEffect } from 'react'
function Example() {
//这里最好使用const来做声明关键字,防止我们意外直接修改state而没有通过set方法去设置。
const [count, setCount] = useState(0);
//useEffect方法接收一个参数,参数为一个函数,这个函数会在Dom渲染的时候调用,包括第一次渲染。
//这里useEffect接收的函数在react中称为副作用函数。
useEffect(()=>{
document.title = `你点击了${count}次!`
})
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Проведем аналогию с компонентом Class:
Например, если вы напишете хук useEffect следующим образом
useEffect(()=>{
document.title = `你点击了${count}次!`
})
В компоненте Class эквивалентно:
//组件挂载到页面上后的生命周期钩子
componentDidMount(){
document.title = `你点击了${this.state.count}次!`
}
//组件State更新之后的生命周期钩子
componentDidUpDate(){
document.title = `你点击了${this.state.count}次!`
}
Здесь useEffect объединяет два жизненных цикла в один, что упрощает код, но также ограничивает гибкость логического кода.
Для этого объяснение, данное официальной документацией React:
Уведомление,В этом классе нам нужно написать повторяющийся код в двух функциях жизненного цикла.
Это потому, что во многих случаях мы хотим сделать то же самое, когда компонент загружается и обновляется. Концептуально мы хотим, чтобы он выполнялся после каждого рендеринга, но компоненты класса React не предоставляют такой метод. Даже если мы извлечем метод, нам все равно придется вызывать его в двух местах.
Реализовать componentWillUnmount с помощью useEffect
Выше описано только как реализовать componentDidMount и componentDidUpdate Как реализовать жизненный цикл componentWillUnmount?
существуетфункция побочных эффектовВ нем можно вернуть функцию, и возвращаемая функция будет componentWillUnmount.
useEffect(()=>{
document.title = `你点击了${count}次!`
let UnmountFn = ()=>{
alert('组件被卸载了!')
}
return UnmountFn
})
Возвращаемая функция будет выполняться только тогда, когда компонент размонтирован.
оптимизация производительности
В компоненте класса componentDidUpdate будет выполняться каждый раз при изменении данных.Мы часто используем изменение, чтобы определить необходимое значение для сохранения производительности, например:
Нам нужно переназначить полное имя при изменении значения имени
componentDidUpdate(prevProps,prevState){
//当发生改变的值是state的name的时候,才继续往下执行
if(prevState.name != this.state.name){
this.setState((state)=>{
return {
fullname:'黄'+ state.name
}
})
}
}
В результате мы можем решить, выполняется ли хук или нет через второй параметр.
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
}, [props.friend.id]); // 仅在 props.friend.id 发生变化时,重新订阅
более точное понимание
Мы проводим аналогию с жизненным циклом компонента класса, чтобы объяснить роль useEffect, что легко понять, но я лично считаю, что это недостаточно точно.
- Компонент componentWillUnmount компонента класса выполняется, когда компонент размонтирован, а функция возвращаемого значения useEffect, аналогичная ей выше, выполняется каждый раз при изменении состояния, но она не будет выполняться при монтировании хука.
- Точки наблюдения разные. Я думаю, что монтирование компонента отличается от монтирования крючка. Даже если кажется, что componentDidMount и useEffect выполняются одновременно, componentDidMount наблюдает за монтированием DOM компонента, а useEffect наблюдает за созданием или обновлением состояния (из другого измерения). понимания, создание и обновление состояния по сути являются заданиями.)
Правила использования хука
Перенесено из официального документа, я думаю, что резюме очень хорошее.
- только всамая внешняя функцияПозвони Хуку. Не вызывайте его в циклах, условных выражениях или подфункциях.
- только вФункциональные компоненты ReactКрюк вызывается. Не вызывайте другие функции JavaScript. (Есть еще одно место для вызова хуков — пользовательские хуки, о которых мы узнаем позже.)
Пользовательский крючок
Мы можем извлечь часть той же логики и внедрить ее в компонент.
Пользовательский крючок - это функция, имя которой начинается с «использования» и может вызывать другие крючки внутри функции.
Пример пользовательского хука:
import React, { useState, useEffect } from 'react';
//这是一个可以通过friendID去判断是否在线的自定义Hook
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
//这里只是返回了isOnline这个属性,当然你连setIsOnline也可以返回出去,可以让组件调用的时候接收这个方法,在必要的时候自行修改Hook的State
return isOnline;
}
Пользовательский хук особенно похож на использование функции, передачу параметра и получение результата.
Разница между определением хука и функции заключается в том, что хук может использовать хуки жизненного цикла и иметь свои собственные данные внутри хука.
Примечание. Новая область состояния создается каждый раз, когда вызывается пользовательский хук (если вы используете useState), поэтому не беспокойтесь о многократном вызове хука и влиянии состояний друг на друга.
Пользовательский хук принимает логику, но не принимает состояние, область действия по-прежнему независима.
Как использовать этот пользовательский крюк в компоненте?
function FriendStatus(props) {
const isOnline = useFriendStatus(props.friend.id);
if (isOnline === null) {
return 'Loading...';
}
return isOnline ? 'Online' : 'Offline';
}
Вы можете сохранить его с помощью переменной. Вам не нужно заботиться о внутренней логике Hook. Он связывает жизненный цикл для вас внутри и помогает вам создать область состояния. Вам не нужно заботиться об этом, вы можете использовать его напрямую.
Разделение кода (будет добавлено)
Ленивая загрузка в React
- динамический импорт( )
- React.lazy( )
- на основе маршрута
Context
Контекст, в переводе означает контекст, у нас иногда бывает такая ситуация, какие-то конкретные состояния, я просто хочу поделиться на дереве компонентов, я не хочу передавать значение слой за слоем, и я не хочу, чтобы он был Глобальная переменная (ведь другим деревьям компонентов эти состояния не нужны), то Context призван решить эту ситуацию.
крепление (производство)
Мы монтируем значение, которое нужно передать вниз, вверху дерева компонентов, и после его монтирования к нему можно получить доступ из компонентов-потомков точки монтирования
использовать (потреблять)
Есть два случая: функциональные компоненты и компоненты класса.
Компонент функции:
Компоненты функций необходимо получать через Context.Consumer.
Компонент класса:
Компонент класса переписывает contextType своего собственного класса и указывает его на контекст, который необходимо получить.
руководство
-
Давайте сначала создадим объект Context, здесьMyContextявляется контекстным объектом
const MyContext = React.createContext('ahreal')
-
Затем мы вешаем Provider вверху дерева компонентов, куда нам нужно передать свойства.(устанавливать)
<MyContext.Provider> <Father> <Son></Son> </Father> </MyContext.Provider>
-
Нам нужны два типа значений.(стоимость)
-
Компонент класса (при условии, что компонент сына является компонентом класса)
class Son extends React.Component{ render(){ let value = this.context } } //需要重写类的contextType,当然这个MyContext如果有需要的话要从定义的地方导入 Son.contextType = MyContext
-
функциональный компонент
function Son(props){ return( <MyContext.Consumer> { value = > ( <div> ... </div> ) } </MyContext.Consumer> ) }
-
Кли (будет добавлено)
...