目录
React.createElement(str,obj,innerHTML)
React
react项目是SPA(Single web Page Application单页网页应用)项目,整个网站只有一个页面,通过路由切换页面中局部的内容,实现页面的变更。
CDN引入
注意下面引入的2个文件,React负责创建元素,ReactDom负责渲染元素到其它元素中。
开发版本
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
压缩版本(生产环境)
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>
React.createElement(str,obj,innerHTML)
利用React创建元素,其中str为标签的名,obj对象上的属性为该标签上挂载的属性,innerHTML为标签内的文本内容。
let h3 = React.createElement('h3',{id:'time',className:'danger'},'时间')
ReactDOM.render(h3,ele)
其中h3为上面React.createElement的返回变量,ele为dom节点。
下面利用ReactDOM渲染h3元素到id为‘yf’的节点上。
let ele = document.getElementById('yf')
ReactDOM.render(h3,ele)
JSX
使用前需要引入babel(使用脚手架创建会都生成好)。
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
再添加babel编译(使用脚手架创建会都生成好)。
<script type="text/babel">
使用
可以理解为用于简化React.createElements函数。
const element = <h1 className = {'hello'}>Hello, world!</h1>;
相当于,注意jsx中使用className给元素添加类名。
let element = React.createElement('h1',{className:'hello'},'Hello, world!')
注意在JSX中一层大括号相当于引用js的环境,和vue中的双重大括号相同。
注释
通过一对大括号加/* */注释。
{/* 注释 */}
数组
jsx中会自动展开数组,并可以直接渲染数组。
注意数组中的JSX元素必须带唯一标识key。
let ele = [<li>1</li>,<li>2</li>,<li>3</li>]
ele.forEach((v,i)=>{v.key=i})//每个元素添加唯一的key
class list extends React.Component {
render() {
return (
<ul>{ele}</ul>
)
}
}
// 渲染为
// <ul>
// <li>1</li>
// <li>2</li>
// <li>3</li>
// </ul>
内联渲染样式
相当于直接给style赋值一个对象,对象中的属性为css样式,小驼峰形式不加横线。
<div style={{ color: 'red', fontSize: '16px' }}></div>
脚手架
要求Node>=8.1和npm>=5.6。
npm i -g create-react-app
创建项目包
注意项目名需要小写,下面react-app为项目名。
create-react-app react-app
安装VScode插件
安装后输入rcc可以自动生成类组件。
JSX 提示
js文件默认是只有js文件提示,想要有JSX文件提示需要像下方一样选中。
类组件
类名需要是大驼峰。类组件要求必须继承父类React.Component。
class HelloWorld extends React.Component {
render(){
return <h1>Hello World!</h1> //React.createDOM('h1',{},Hello World!') 也行
}
}
<HelloWorld /> //使用方式
接收参数
class HelloWorld extends React.Component {
constructor(props){
this.props = props //可以不用写,在父类中实现了
}
render(){
return <h1>Hello World!</h1> //React.createDOM('h1',{},Hello World!') 也行
}
}
new HelloWorld({name:'yf'}) //等同于<HellorWorl name='yf' />
则类中this.props.name等于'yf' 。
state状态
React 把组件看成是一个状态机(State Machines)。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。React 里只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。
注意状态的修改和vue中的不同(vue中会自动重新渲染),react只有通过setState函数设置状态才会重新渲染。因为是重新渲染,故可以通过setState传入空对象,让之前直接通过this.state更改的状态生效。
setState(state,callback)
对组件 state 的更改排入队列,并通知 React 需要使用更新后的 state 重新渲染此组件及其子组件。state是需要合并的对象(注意相当于Object.assign,不是替换),callback是state更新完后的回调函数(建议使用 componentDidUpdate替代)
。当需要使用到props和state时,state可以为一个函数例如下面,函数的返回对象为需要合并的对象。
this.setState((state, props) => {
return {counter: state.counter + props.step};
});
注意在调用 setState()
后立即读取 this.state的值不一定会改变。
例如下面state.counter的值始终是不会变的。
this.setState({counter: state.counter++});
相当于 this.setState({counter: state.counter})先执行,再执行this.counter=this.counter+1两行代码,由于this.setState是异步的,所以每次都会将值重置。
defaultProps
defaultProps
可以为 Class 组件添加默认 props。这一般用于 props 未赋值,但又不能为 null
的情况。例如:
class CustomButton extends React.Component {
// 定义方法一
static defaultProps = {
color: 'blue'
}
// ...
}
}
// 定义方法二
CustomButton.defaultProps = {
color: 'blue'
};
如果未提供 props.color
,则默认设置为 'blue'
render() {
return <CustomButton /> ; // props.color 将设置为 'blue'
}
如果 props.color
被设置为 null
,则它将保持为 null
render() {
return <CustomButton color={null} /> ; // props.color 将保持是 null
}
this.forceUpdate(callback)
强制让组件重新渲染,callback为重新渲染后的回调函数。
函数组件
函数名要大驼峰写法。返回React.createElements生成的对象。
function HelloWorld(){
return <h1>Hello World!</h1> //React.createDOM('h1',{},Hello World!') 也行
}
<HelloWorld /> //使用方式
接收参数
函数组件中可以接收一个参数,该参数为一个对象,属性为组件使用时上面的属性。
function HelloWorld(props){
return <h1>Hello World!</h1> //React.createDOM('h1',{},Hello World!') 也行
}
HelloName({name:'yf'}) //等同于<HellorWorl name='yf' />
则props.name等于'yf'。
defaultProps
function CustomButton(){
// ...
}
CustomButton.defaultProps = {
color: 'blue'
};
props.children
获取调用组件时填充到组件标签内部的内容,类似于vue中的slot插槽。
<Person>组件内部的内容</Person>
const Person = (props) => {
return ( <div>(props.children)</div> );
}
注意点
函数组件里面不要直接写setInterval和useState中设置state值的函数,这会导致定时器越来越多,和组件不停被重新渲染。
例如下面会产生setIterval(()=>{setCount(1)})、setIterval(()=>{setCount(2)})、3、4、5...等越来越多定时器。
function Counter() {
const [count, setCount] = useState(0);
setInterval(() => {
setCount(count + 1);
}, 1000);
// 造成的后果就是能一直更新count,但是每一轮循环都会执行上面这行代码,
//定时器越来越多,然后,就卡死啦,而且每个定时器都会执行一遍,
//那么屏幕上的数字每秒都会在跳,可以试试看
return <h1>{count}</h1>;
}
事件
标签上添加on事件名=‘方法名’来绑定事件。
注意事件名大写,绑定时不能在函数后加括号,加了会在创建时执行,触发指定事件时不会被执行。
绑定this
类组件中使用this需要注意this的指向,因为事件的触发都是window,this指向的是事件的调用者,故为window,所以使用时需要绑定this指向。
bind绑定this
下面可以在constructor中绑定this也可以在render中绑定this。
class Demo extends React.Component {
constructor(){
//super(props);
//this.show = this.show.bind(this);
}
show(){
console.log('点击')
}
render(){
return <button onClick={ this.show.bind(this) }>点击事件</button>
}
}
箭头函数绑定this
class Demo extends React.Component {
show(){
console.log('点击')
}
render(){
return <button onClick={ ()=>{ this.show() }}>点击事件</button>
}
}
事件池
React对事件对象进行了包装,对象会被放入池中统一管理。这意味着包装的事件对象可以被复用,当所有事件处理函数被调用之后,其所有属性都会被置空。React17开始移除了该特性。
例如下面代码e为undefined,会报错
function handleChange(e) {
// This won't work because the event object gets reused.
setTimeout(() => {
console.log(e.target.value); // Too late!
}, 100);
}
如果你需要在事件处理函数运行之后获取事件对象的属性,你需要调用 e.persist()
:
function handleChange(e) {
// Prevents React from resetting its properties:
e.persist();
setTimeout(() => {
console.log(e.target.value); // Works
}, 100);
}
Hooks
React中Hooks详解(useState、useEffect、useContext、useRef详解)_AIWWY的博客-CSDN博客
Ref使用详解
https://blog.csdn.net/AIWWY/article/details/123404928
React生命周期和错误处理方法
https://blog.csdn.net/AIWWY/article/details/123338490
注意点
img标签
注意webpack打包工具要求本地图片使用require来引入,vue会自动生成,而react没有做处理,所以需要使用require引入。
<img src={ require(url) }>