首页
统计
赞助
留言
关于
更多
友链
壁纸
直播
Search
1
Joe — 一款个人类型Typecho主题
32,765 阅读
2
Joe开源目录程序系统
12,001 阅读
3
Typecho自定义后台编辑器功能
8,394 阅读
4
Joe主题实现自动更新
7,612 阅读
5
Joe主题自定义搭配色教程
4,511 阅读
WEB前端
CSS
React
Vue 2.0
Vue 3.0
JavaScript
TypeScript
Typecho
小程序
苹果CMS
其他
生活
登录
Search
https://78.al
累计撰写
76
篇文章
累计收到
3,760
条评论
首页
栏目
WEB前端
CSS
React
Vue 2.0
Vue 3.0
JavaScript
TypeScript
Typecho
小程序
苹果CMS
其他
生活
页面
统计
赞助
留言
关于
友链
壁纸
直播
搜索到
6
篇与
React
的结果
2021-06-08
React学习笔记六
React拓展 - setStatesetState更新状态的两种写法1、setState({}, [callback])export default class Test extends Component { state = {count: 0} add = () => { const { count } = this.state this.setState({ count: 8 }) console.log(this.state.count) // 0 因为setState是异步的,所以会先执行这个 // 如果想要在setState操作后,拿state里的值进行操作,需要使用第二个回调函数或async await实现 this.setState({ count: 8 }, () => { console.log(this.state.count) // 8 }) } }2、setState(updater, [callback])export default class Test extends Component { state = {count: 0} add = () => { // 通过函数式,可以获取到state和props this.setState((state, props) => { console.log(state, props) return { count: state.count + 1 } }, () => { console.log(this.state.count) // 1 }) } }React拓展 - lazyLoad路由懒加载import {Component, lazy, Suspense} from "react" // 懒加载路由模块 const Home = lazy(() => import("./Home/index")) const About = lazy(() => import("./About/index")) export default class Test extends Component { render() { return ( <div> {/* Suspense 用于网络不好的时候,显示一个loading加载 */} <Suspense fallback={<h1>Loading...</h1>}> <Route path="/home" component={Home}> <Route path="/about" component={About}> </Suspense> </div> ) } }React拓展 - State HookState Hook 为了让使用者在函数式组件里使用stateimport React from 'react'; export default function Test2() { // React.useState() 用于初始化一个值,返回一个数组 // 数组第一个值为初始化的值 // 第二值为一个函数,用于修改第一个值 const [count, setCount] = React.useState(0); const [name, setName] = React.useState('杜恒'); // 点击事件的回调 const changeCount = () => setCount(count + 1); const changeName = () => setName('帅气的杜恒'); return ( <div> <h2>当前值为:{count}</h2> <button onClick={changeCount}>+ 1</button> <hr /> <h2>当前名为:{name}</h2> <button onClick={changeName}>改名</button> </div> ); }React拓展 - Effect HookEffect Hook 为了让使用者在函数式组件里使用生命周期钩子import React from 'react'; export default function Test2() { const [count, setCount] = React.useState(0); // React.useEffect 接收两个参数 // 第一个参数为函数,这个函数可以用作2个生命周期 // componentDidMount 或 componentDidUpdate // 第二个参数为数组,这个数组用于监听state里的值 // 如果为空数组,则第一个参数当componentDidMount使用(只调用一次) // 如果第二个参数没写或数组有值,则第一个参数当componentDidUpdate使用 React.useEffect(() => { let timer = setInterval(() => { setCount(count => count + 1); }, 1000); // 当return函数出去时,这个return出去的函数就可以当componentWillUnmount使用 return () => { clearInterval(timer); }; }, []); return ( <div> <h2>当前值为:{count}</h2> </div> ); }React拓展 - Ref HookRef Hook 和类式组件里面的createRef一样import React from 'react'; export default function Test2() { const inputRef = React.useRef(); const show = () => console.log(inputRef); return ( <div> <input type="text" ref={inputRef} /> <button onClick={show}>点击提示</button> </div> ); }React拓展 - Fragment用于多个标签时包裹使用import React, {Fragment} from 'react'; export default function Test2() { return ( <Fragment> <input type="text" /> <input type="text" /> </Fragment> ); }上面的写法可以写成下面的,直接使用空标签import React, {Fragment} from 'react'; export default function Test2() { return ( <> <input type="text" /> <input type="text" /> </> ); }React拓展 - ContextContext 用于祖组件向后台组件通信import React, { Component } from 'react'; // 1. 创建TestContext容器 const TestContext = React.createContext(); export default class A extends Component { state = { name: '杜恒' }; render() { return ( <div style={{ background: 'orange', padding: 10 }}> 我是A组件 {/* 2. 通过 Provider 将所有的state传入到后代组件里 */} <TestContext.Provider value={this.state}> <B /> </TestContext.Provider> </div> ); } } class B extends Component { render() { return ( <div> 我是B组件 <C /> </div> ); } } // 第一种方式 class C extends Component { /* 3. 申明使用context */ static contextType = TestContext; render() { console.log(this.context); // {name: "杜恒"} return <div>我是C组件</div>; } } // 第二种方式 function C() { return ( <div> <TestContext.Consumer> { value => console.log(value) } </TestContext.Consumer> </div> ) }React拓展 - 组件优化组件有以下2个问题组件内执行了setState,即使不改变状态数据,也会触发render更新父组件render发生更新,会导致子组件的render也会触发由于render受shouldComponentUpdate的阀门控制,因此需要在shouldComponentUpdate钩子里进行操作import { Component } from 'react'; export default class A extends Component { state = { count: 0 }; /* 赋值一个空对象,并没有改变state的值,也会触发更新 */ add = () => this.setState({}); /* 通过控制shouldComponentUpdate的返回值,控制是否触发render */ shouldComponentUpdate(nextProps, nextState) { console.log(nextProps, nextState); return !this.state.count === nextState.count; } render() { console.log('render函数被触发了'); return <button onClick={this.add}>{this.state.count}</button>; } }{callout color="#ab72da"}在state里的值少的时候,可以这样写,但是当数据多的时候就不行了,因此另一种方案是将 Component 替换成 PureComponent。PureComponent 里已经默认实现了 shouldComponentUpdate 里的逻辑,上面的写法可以改成下面的写法{/callout}import { PureComponent } from 'react'; export default class A extends PureComponent { state = { count: 0 }; add = () => this.setState({}); render() { console.log('render函数被触发了'); return <button onClick={this.add}>{this.state.count}</button>; } }React拓展 - Render Propsimport { PureComponent } from 'react'; export default class A extends PureComponent { render() { return ( <div> <h3>我是A组件</h3> <B render={name => <C name={name} />}></B> </div> ); } } class B extends PureComponent { state = { name: '杜恒' }; render() { return ( <div> <h3>我是B组件</h3> {/* 类似插槽的功能 */} {this.props.render(this.state.name)} </div> ); } } class C extends PureComponent { render() { console.log(this.props); return <div>我是C组件</div>; } }错误边界错误边界用于当子组件出错时,控制错误范围在父组件,不会影响到其他的组件。错误边界只能在生产环境使用,开发环境会一闪而过import { PureComponent } from 'react'; export default class A extends PureComponent { /* 父组件定义一个状态,用于判断是否出错 */ state = {hasError: ''}; /* 当后代组件生命周期里有错误时,会触发该函数 */ static getDerivedStateFromError(error) { return { hasError: error }; } /* 这里可以抓捕到错误后,将错误发送给服务器,服务器在通知到钉钉等 */ componentDidCatch() { console.log('组件发生错误!') } render() { return ( <div> <h3>我是A组件</h3> {/* 动态渲染组件 */} {this.state.hasError ? <h2>子组件出错</h2> : <B />} </div> ); } } class B extends PureComponent { state = { name: '杜恒' }; render() { return ( <div> <h3>我是B组件</h3> {this.state.name.map(() => ( <span>666</span> ))} </div> ); } }
2021年06月08日
241 阅读
0 评论
2 点赞
2021-06-07
React学习笔记五
Redux什么是ReduxRedux是一个专门用于做状态管理的JS的库可以用在Vue、React、Angular中,但最常与React使用作用:集中式管理React应用中多个组件共享的状态安装redux 和 react-reduxnpm i redux -S npm i react-redux -SRedux使用1、src目录下创建redux文件夹,redux文件夹内创建reducers文件夹,用于管理reducers,例如新建一个count的reducer{callout color="#51d2ad"}reducer可以初始化状态,也可以操作状态{/callout}// 第一次prevState会默认为undefined,因此此时可以为其赋值,初始化一个状态值 // 这里的action就是第二步action传递过来的对象 export default function countReducer(prevState = 0, action) { switch (action.type) { case 'add': return prevState + action.data; default: return prevState; } }2、redux文件夹内创建actions文件夹,用于管理actions,例如新建一个count的action// action的作用是将此对象分发给store,接着reducer会进行加工处理 export const createAddAction = data => ({ type: 'add', data });3、redux文件夹内创建store文件// createStore 用于创建store // combineReducers 用于整合多个reducer import { createStore, combineReducers } from 'redux'; import countReducer from './reducers/count'; const allReducer = combineReducers({ count: countReducer }); export default createStore(allReducer);4、组件内获取store里的值和分发事件给reducerimport { Component } from 'react'; // 用于连接redux import { connect } from 'react-redux'; // 用于分发事件 import { createAddAction } from '../../redux/actions/count'; class Count extends Component { add = () => { this.props.add(1); }; render() { const { count } = this.props; return ( <div> <div>当前求和为:{count}</div> <button onClick={this.add}>+</button> </div> ); } } // state => ({ count: state.count }) state 就是redux里的内容,会将内容传递给Count组件 // { add: createAddAction } 会传递一个add事件给Count组件,Count组件内调用add方法会调用createAddAction,接着React-Redux会分发这个事件给Reducer export default connect(state => ({ count: state.count }), { add: createAddAction })(Count);5、入口文件内,添加Provider供全局公用storeimport store from './redux/store'; import { Provider } from 'react-redux'; ReactDOM.render( <Provider store={store}> <App /> </Provider>, document.querySelector('#root') );
2021年06月07日
150 阅读
0 评论
2 点赞
2021-06-04
React学习笔记四
React-Router-Dom首先需要安装路由的依赖库,注意名字为 react-router-domnpm i react-router-dom -S标签方式的实现路由控制1、首先 index.js 里面为 组件包裹一个 BrowserRouter 或 HashRouter,两者区别在于地址栏有没有 # 的链接,这样保证整个项目里的路由都是同一个路由器管理import { BrowserRouter } from 'react-router-dom'; import App from './App'; ReactDOM.render( <BrowserRouter> <App /> </BrowserRouter>, document.querySelector('#root') );2、App.jsx 里面通过标签实现路由控制{callout color="#4eda96"}在路由组件(例如About和Home组件)里面,会默认接收到4个props属性{/callout}import { Component } from 'react'; import { Link, Route } from 'react-router-dom'; import About from './views/About/About'; import Home from './views/Home/Home'; export default class App extends Component { render() { return ( <div> {/* 点击跳转到对应路由 */} <NavLink to="/about" activeClassName="current">About</NavLink> <NavLink to="/home" activeClassName="current">Home</NavLink> {/* 使用switth可以提高匹配效率 */} <Switch> {/* 根据不同的路由地址,显示对应的组件 */} <Route path="/about" component={About} /> <Route path="/home" component={Home} /> </Switch> </div> ); } }Tips:解决二级路由刷新页面资源丢失的3种办法public/index.html 里将 ./assets 类型的改为 /assetspublic/index.html 里将 ./ 改为 %PUBLIC_URL%public/index.html 里将 BrowserRouter 改为 HashRouter路由重定向import { Component } from 'react'; import { Link, Route, Redirect } from 'react-router-dom'; import About from './views/About/About'; import Home from './views/Home/Home'; export default class App extends Component { render() { return ( <div> <NavLink to="/about" activeClassName="current">About</NavLink> <NavLink to="/home" activeClassName="current">Home</NavLink> <Switch> <Route path="/about" component={About} /> <Route path="/home" component={Home} /> {/* 当所有路由都没有匹配上,会执行重定向 */} <Redirect to="/about"/> </Switch> </div> ); } }路由传参1、向路由组件传递params参数News组件import Detail from './Detail/Detail'; export default class News extends Component { render() { return ( <div> <Link to="/home/news/detail/001">新闻1</Link> <Link to="/home/news/detail/002">新闻2</Link> <Link to="/home/news/detail/003">新闻3</Link> {/* 通过冒号动态接收 */} <Route path="/home/news/detail/:id" component={Detail} /> </div> ); } }Detail组件export default class News extends Component { render() { {/* 此处会接收到传递的参数 */} console.log(this.props.match.params); return <div>{this.props.match.params.id}</div>; } }2、向路由组件传递search参数News组件export default class News extends Component { render() { return ( <div> <Link to="/home/news/detail/?id=001">新闻1</Link> <Link to="/home/news/detail/?id=002">新闻2</Link> <Link to="/home/news/detail/?id=003">新闻3</Link> <Route path="/home/news/detail" component={Detail} /> </div> ); } }Detail组件export default class News extends Component { render() { console.log(this.props.location.search); return <div>Test</div>; } }3、向路由组件传递state参数,当清除浏览器记录后,会丢失数据News组件export default class News extends Component { render() { return ( <div> <Link to={{ pathname: '/home/news/detail', state: { id: '001' } }}>新闻1</Link> <Link to={{ pathname: '/home/news/detail', state: { id: '002' } }}>新闻2</Link> <Link to={{ pathname: '/home/news/detail', state: { id: '003' } }}>新闻3</Link> <Route path="/home/news/detail" component={Detail} /> </div> ); } }Detail组件export default class News extends Component { render() { console.log(this.props.location.state); return <div>Test</div>; } }编程式路由1、压栈式跳转(有历史记录)export default class News extends Component { linkTo = id => { this.props.history.push({ pathname: '/home/news/detail', state: { id } }); }; render() { return ( <button onClick={() => this.linkTo('001')}>新闻1</button> ); } }2、非压栈式跳转(直接替换,无历史记录)export default class News extends Component { linkTo = id => { this.props.history.replace('/home/news/detail',{ id }); }; render() { return ( <button onClick={() => this.linkTo('001')}>新闻1</button> ); } }一般组件增加路由功能{callout color="#986de8"}默认情况下,一般组件是没有路由功能的,因此就需要借助 withRouter 来实现路由功能{/callout}import { withRouter } from 'react-router-dom'; class Test extends Component { go = () => { console.log(this.props) }; render() { return <button onClick={() => this.go}>新闻1</button> } } export default withRouter(Test)
2021年06月04日
163 阅读
0 评论
2 点赞
2021-06-01
React学习笔记三
React脚手架生成的index.js内容简介import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; import reportWebVitals from './reportWebVitals'; ReactDOM.render( // 开启严格模式,开启后,可以检测到app组件里的规范,例如使用字符串的 ref="" <React.StrictMode> <App /> </React.StrictMode>, document.getElementById('root') ); // 用于记录页面性能 reportWebVitals();子组件向父组件传值1、父组件export default class P extends Component { addTodo = name => { const { todos } = this.state; }; render() { return ( <div> <Header addTodo={this.addTodo}/> </div> ); } }2、子组件export default class Header extends Component { handleClick = () => { this.props.addTodo(88888) } render() { return ( <div onClick={this.handleClick}> Test </div> ); } }兄弟组件之间传值(消息订阅与发布){message type="info" content="消息订阅与发布,通常使用 PubSubJS 库进行实现"/}例如有两个兄弟组件 A 和 B。1、A组件需要接收B组件传递过来的数据,那么A组件需要先订阅一个消息export default class A extends Component { state = { items: [], isFirst: true, isLoading: false, error: '' }; componentDidMount() { // 订阅一个叫做 STATE 的消息 PubSub.subscribe('STATE', (msg, state) => { console.log(msg, state) if (msg === 'STATE') this.setState(state); }); } render() { return ( <div></div> ); } }2、B组件发布消息给A组件export default class Search extends Component { render() { return ( <div> <button onClick={this.searchUser}>搜索</button> </div> ); } /* 搜索用户 */ searchUser = () => { PubSub.publish('STATE', { isFirst: false, isLoading: true, error: '' }); }; }通过reduce实现数组的统计例如统计数组里面done为true的数量const arr = [ { name: 'a', done: true }, { name: 'b', done: true }, { name: 'c', done: false } ] const doneCount = arr.reduce((prev, current) => { return prev + (current.done ? 1 : 0) }, 0) console.log(doneCount) // 2React中代理服务器配置跨域的2种方式{callout color="#7f68f3"}配置跨域的原理:例如当前的项目地址为:http://localhost:3000,会开启一个微型的 http://localhost:3000 代理服务器,当发送请求后,会将请求发送给这个微型服务器,接着由微型服务器再发送给服务端,最后这个微型服务器将结果再转发给当前项目地址。这个微型服务器因为没有ajax引擎,所以不会有跨域阻断问题{/callout}1、通过修改package.json方式例如,需要请求到的服务器的域名及端口为 http://localhost:5000 在package.json文件中,添加以下的选项{ ..., "proxy": "http://localhost:5000", "proxy": "需要代理的服务器域名和端口号" }例如,当前启动项目的地址是 http://localhost:3000/接着将之前的请求地址改为本地的地址import { Component } from 'react'; import axios from 'axios'; export default class App extends Component { getData = async () => { try { // const res = await axios.get('http://localhost:5000/students'); 修改前 const res = await axios.get('http://localhost:3000/students'); // 修改后 const res = await axios.get('/students'); // 或者改成这种 console.log(res); } catch (e) { console.log(e); } }; render() { return <button onClick={this.getData}>click</button>; } }{callout color="#4da9ef"}Tips:代理服务器发送请求时,会优先public文件夹寻找,如果有对应的文件,则直接请求对应的文件,如果没有,才向服务端发送请求。例如请求 localhost:3000/index.html,并不会直接发送代理发送请求给 localhost:5000/index.html 而是直接请求了 public 文件夹里的 index.html 文件{/callout}2、通过 setupProxy 文件先在 src 下创建 setupProxy.js 的文件const proxy = require('http-proxy-middleware'); module.exports = function (app) { app.use( /* 遇见 /api1 前缀的请求,就会触发该配置 */ proxy('/api1', { /* 将请求转发给 http://localhost:5000 */ target: 'http://localhost:5000', /* * 控制服务器收到请求头的中 Host 的值 * 为 true 的时候,服务器端接收到的请求 Host 为 http://localhost:5000 * 为 false 的时候,服务器端接收到的请求 Host 为 http://localhost:3000 */ changeOrigin: true, /* * 重写请求路径 * 将 /api1 替换成空 */ pathRewrite: { '^/api1': '' } }) ); };发送请求import { Component } from 'react'; import axios from 'axios'; export default class App extends Component { getData = async () => { try { // 上面的代理后,会将此处的 api1 替换成空,实际请求的地址为 http://localhost:5000/students const res = await axios.get('/api1/students'); console.log(res); } catch (e) { console.log(e); } }; render() { return <button onClick={this.getData}>click</button>; } }React脚手架配置代理.md
2021年06月01日
230 阅读
0 评论
2 点赞
2021-05-31
React学习笔记二
通过柯里化函数实现带参数的事件绑定class Login extends React.Component { state = { username: '', password: '' } saveFormData = (type) => { /* 返回一个函数供事件回调 */ return (event) => { event.persist() this.setState({ [type]: event.target.value }) } } render() { return ( <div> <input placeholder="用户名" onChange={this.saveFormData('username')} /> <input placeholder="密码" onChange={this.saveFormData('password')} /> </div> ) } } ReactDOM.render(<Login />, document.querySelector("#main"))不用柯里化实现带参数的事件绑定class Login extends React.Component { state = { username: '', password: '' } saveFormData = (type, value) => { this.setState({ [type]: value }) } render() { return ( <div> <input placeholder="用户名" onChange={(event) => { this.saveFormData('username', event.target.value) }} /> <input placeholder="密码" onChange={(event) => { this.saveFormData('password', event.target.value) }} /> </div> ) } } ReactDOM.render(<Login />, document.querySelector("#main"))组件生命周期(旧)1、单个组件时的生命周期钩子class Count extends React.Component { /* 优先执行 */ constructor(props) { console.log('Count---constructor'); super(props) this.state = { count: 0 } } /* 组件即将挂载的钩子 */ componentWillMount() { console.log('Count---componentWillMount'); } /* 组件渲染的钩子 */ render() { console.log('Count---render'); return ( <div> <h2>当前值为:{this.state.count}</h2> <button onClick={this.addCount}>点击 + 1</button> <button onClick={this.deleteComponent}>卸载组件</button> <button onClick={this.forceUpdateComponent}>强制更新</button> </div> ) } /* 组件渲染完毕的钩子 */ componentDidMount() { console.log('Count---componentDidMount'); } /* 组件将要卸载的钩子 */ componentWillUnmount() { console.log('Count---componentWillUnmount'); } /* * * 控制组件更新的阀门 * 每次执行setState更新state的时候,都会询问这个阀门 * 如果返回true,则允许渲染,否则反之 * 如果没有写这个钩子,则React底层会默认补充这个函数,并且返回true * */ shouldComponentUpdate() { console.log('Count---shouldComponentUpdate'); return true } /* 组件将要更新的钩子 */ componentWillUpdate() { console.log('Count---componentWillUpdate'); } /* 组件更新完毕的钩子 */ componentDidUpdate() { console.log('Count---componentDidUpdate'); } addCount = () => { let { count } = this.state this.setState({ count: count + 1 }) } deleteComponent = () => { ReactDOM.unmountComponentAtNode(document.querySelector('#main')) } forceUpdateComponent = () => { /* * 强制更新组件 * 不经过阀门,不需要修改state的状态 * */ this.forceUpdate() } }2、父子组件的时候,子组件有一个componentWillReceiveProps钩子/* A是父组件 */ class A extends React.Component { state = { name: '杜恒' } render() { return ( <div> <h2>我是A组件</h2> <button onClick={this.changeName}>点击传递Props</button> <B name={this.state.name} /> </div> ) } changeName = () => { this.setState({ name: '哈哈哈' }) } } /* B是子组件 */ class B extends React.Component { componentWillReceiveProps(props) { console.log('B组件触发了componentWillReceiveProps', props); } render() { return <div>我是B组件,接收到了{this.props.name}</div> } }3、旧版本生命周期的总结初始化阶段先执行 constructor 初始化接着执行 componentWillMount 组件将要挂载接着执行 render 组件渲染接着执行 componentDidMount 组件渲染完毕(常用)更新阶段先执行 shouldComponentUpdate 组件是否允许更新阀门接着执行 componentWillUpdate 组件将要更新接着执行 render 渲染组件接着执行 componentDidUpdate 组件更新完毕卸载阶段执行 componentWillUnmount 组件将要卸载(常用)组件生命周期(新)新版生命周期的总结初始化阶段先执行 constructor 初始化接着执行 getDerivedStateFromProps 从props里面获取state的派生(将props映射到state上)接着执行 render 渲染组件接着执行 componentDidMount 组件渲染完毕更新阶段先执行 getDerivedStateFromProps 从props里面获取state的派生(将props映射到state上)接着执行 shouldComponentUpdate 组件能否被更新接着执行 render 渲染组件接着执行 getSnapshotBeforeUpdate 在更新完毕前获取当前快照(当前信息,并将信息传递给更新完毕钩子)接着执行 componentDidUpdate 组件更新完毕(可以获取到上面的快照信息)卸载阶段执行 componentWillUnmount 组件即将卸载钩子{callout color="#ff6800"}相对比旧版本的生命周期钩子而言删除了3个用不上的will钩子 componentWillMount componentWillUpdate componentWillReceiveProps并增加了2个新的生命周期钩子 getDerviedStateFromProps getSnapshotBeforeUpdate{/callout}class Count extends React.Component { constructor(props) { console.log('constructor执行了'); super(props) this.state = { count: 0 } } /* 如果想让state的值和props的值一致,那么可以使用这个钩子 */ static getDerivedStateFromProps(props, state) { console.log('getDerviedStateFromProps', props, state); return null } render() { console.log('render执行了'); return ( <div> <h2>当前值为:{this.state.count}</h2> <button onClick={this.addCount}>点击 + 1</button> </div> ) } /* 组件渲染完毕 */ componentDidMount() { console.log('componentDidMount执行了'); } /* 组件能否被更新 */ shouldComponentUpdate() { console.log('shouldComponentUpdate执行了'); return true } /* * * 在更新前获取快照 * 在即将发生dom更新前调用这个钩子, * 并return一个快照值 * 这个快照值,可以在组件更新完毕里面获取 * 在这个钩子里,可以获取到当前的信息 * */ /* 组件更新完毕 */ componentDidUpdate(prevProps, prevState, snapshot) { console.log('componentDidUpdate执行了', prevProps, prevState, snapshot); } addCount = () => { let { count } = this.statesafds this.setState({ count: count + 1 }) } }
2021年05月31日
191 阅读
1 评论
0 点赞
2021-05-20
React学习笔记一
JSX语法1、标签不能添加引号,换行用括号包裹,并且只有一个根标签const H1 = <h1>标题</h1> const Div = ( <div> <h1>H1</h1> <h2>H2</h2> </div> )2、变量使用花括号const id = 1 const name = "杜恒" const Div = <div data-id={id}>{name}</div>3、外连样式与内联样式// 使用class时,需要写className的方式 const Div = <div className="box"></div> // 内联样式时,需要成变量内包对象方式 const Div2 = <div style={{ color: '#ff6800', fontSize: '30px' }}>Test</div>4、单标签需要闭合const div = ( <div> <br /> <input /> </div> )5、循环数组const arr = ['vue', 'react', 'jquery'] const Ul = ( <ul> { arr.map(item => <li key={item}>{item}</li>) } </ul> )组件1、函数式组件(简单组件<在hooks里面可以实现3大属性>)function Test() { console.log(this) // undefined return <div>Test组件</div> } ReactDOM.render(<Test />, document.querySelector("#main"))2、类式组件(复杂组件)class Test extends React.Component { render() { console.log(this); // 由Test类创造的组件实例对象 return <div>Test组件</div> } } /* * * 首先解析Test标签,并找到Test的类 * 接着React内部,会去new这个Test类,接着会初始化实例对象上的render方法 * */ ReactDOM.render(<Test />, document.querySelector("#main"))组件实例三大属性 stateclass Weather extends React.Component { render() { console.log(this); return <h1>今天天气很炎热</h1> } } ReactDOM.render(<Weather />, document.querySelector("#main"))打印类的实例对象上的this,可以看到实例对象身上挂了一个state属性,默认值为nullclass Weather extends React.Component { /* constructor根据页面上有多少个实例就调用几次 */ constructor(props) { super(props) /* 向当前实例上挂载一个属性 */ this.state = { isHot: false } /* 解决changeWeather中的this指向undefined的问题 */ this.changeWeather = this.changeWeather.bind(this) } /* render调用1 + n次,第一次进入默认执行一次,后state更新触发render */ render() { /* this指向当前的实例,于是可以通过this访问到state属性 */ console.log(this); /* onClick绑定的函数不能加括号,否则会直接执行函数! */ return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1> } /* * * changeWeather挂载在Weather的原型对象上,供Weather的实例对象使用, * 只有Weather的实例对象去调用这个方法,函数内的this才会指向Weather的实例对象 * 由于在class中会将函数开启局部严格模式,因此changeWeather里的this会指向undefined * 但需要解决这个this指向问题,因此就需要在上方初始化的时候,改变this的指向 * */ changeWeather() { console.log(this); /* * 状态不可直接更改! * this.state.isHot = !this.state.isHot × */ this.setState({ isHot: !this.state.isHot }) } } ReactDOM.render(<Weather />, document.querySelector("#main"))上面的代码可以简写成下方代码class Weather extends React.Component { // 直接赋值给实例化对象身上 state = { isHot: false } // 直接赋值给实例化对象身上 changeWeather = () => { console.log(this); // this 指向当前实例化后的对象 this.setState({ isHot: !this.state.isHot }) } render() { return <h1 onClick={this.changeWeather}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1> } } ReactDOM.render(<Weather />, document.querySelector("#main"))组件实例三大属性 props1、props的基本使用class Person extends React.Component { render() { return <h1 data-age={this.props.age} data-sex={this.props.sex}>{this.props.name}</h1> } } const person = { age: 18, sex: "男" } ReactDOM.render(<Person name="杜恒" {...person} />, document.querySelector("#main"))2、props属性限制class Person extends React.Component { /* 限制props传入的类型 */ static propTypes = { name: PropTypes.string.isRequired, age: PropTypes.number, sex: PropTypes.string } /* props未传的时候的默认值 */ static defaultProps = { age: 18, sex: "男" } render() { return ( <ul> <li>姓名:{this.props.name}</li> <li>年龄:{this.props.age}</li> <li>性别:{this.props.sex}</li> </ul> ) } } ReactDOM.render(<Person name="杜恒" age={23} />, document.querySelector("#main"))3、定义组件时,如果写了构造器,需要将props传递给父类,否则可能会出现找不到 this.props 的bugclass Person extends React.Component { constructor() { super() console.log(this.props); // undefined } render() { return <h1>{this.props.name}</h1> } }4、函数式组件接收propsfunction Person(props) { console.log(props); return <h1>{props.name}</h1> } ReactDOM.render(<Person name="杜恒" />, document.querySelector("#main"))组件实例三大属性 refs1、字符串形式的 ref (已废弃)class Test extends React.Component { /* 点击显示左侧input的内容 */ showInputValue = () => { console.log(this); alert(this.refs.input.value) } showBlurInputValue = e => { e.persist(); console.log(e); alert(e.target.value) } render() { return ( <ul> <li> <input ref="input" type="text" /> <button onClick={this.showInputValue}>点击显示左侧提示</button> </li> <li> <input onBlur={this.showBlurInputValue} type="text" placeholder="失去焦点弹出提示" /> </li> </ul> ) } }2、回调函数形式的 refclass Test extends React.Component { showInputValue = () => { console.log(this.input); alert(this.input.value) } render() { return ( <div> <input ref={node => (this.input = node)} type="text" /> <button onClick={this.showInputValue}>点击显示左侧提示</button> </div> ) } }内联方式的ref里的回调函数,在更新状态的时候,会触发2次,第一次会得到null,第二次才得到当前的节点,如果想避免这个问题,可以将函数写成class的方式,上面的方式可以写成下面这种class Test extends React.Component { /* 点击显示左侧input的内容 */ showInputValue = () => { console.log(this.input); alert(this.input.value) } /* 保存input */ saveInputRef = (node) => { this.input = node } render() { return ( <div> <input ref={this.saveInputRef} type="text" /> <button onClick={this.showInputValue}>点击显示左侧提示</button> </div> ) } }3、createRef 形式class Test extends React.Component { myRef = React.createRef() /* 点击显示左侧input的内容 */ showInputValue = () => { console.log(this.myRef); alert(this.myRef.current.value) } render() { return ( <div> <input ref={this.myRef} type="text" /> <button onClick={this.showInputValue}>点击显示左侧提示</button> </div> ) } } ReactDOM.render(<Test />, document.querySelector("#main"))
2021年05月20日
149 阅读
1 评论
1 点赞