react是什么
- React是一个声明式,高效且灵活的用于构建用户界面的JavaScript组件库,使用react可以将一些简短,独立的代码片段合成复杂的UI界面,这些代码片段被称作组件
react介绍
- facebook公司的开源项目 2013年5月 开源(Angar2012年开源,vue2016年开源)
- js框架(MVC框架,专注于V)
- 能够构建大型应用
- vue面向中小型应用
- 市场项目(饿了吗)
react特点
- 声明式 (虚拟DOM,数据改变,更新视图)
- 组件化 (component使用js编写,而不是template–使传递数据更轻松,状态与DOM分离)
- 一次学习,随处编写
当前版本
16.x
脚手架create-react-app
- react使用到了jsx语法(浏览器不支持,需使用webpack编译成js语法)
创建项目
- 全局安装create-react-app
- npm install -g create-react-app
- 创建项目
- create-react-app 项目名
- 非全局安装创建项目
- npx create-react-app 项目名(临时安装react脚手架)
安装的内容
- react:react的顶级库
- react-dom:将jsx编辑的react编译成浏览器能识别的js和标签(jsx:js+xml; react有很多的运行环境,比如app端的react-native)
- react-script:react应用程序的运行脚本(webpack等)
react的脚本命令
- yarn start 运行开发环境
- yarn bulid 运行生产环境
- yarn test 运行测试环境
- yarn eject react配置的抽离(不可逆)
- 从node_modules的react-script文件中抽离配置文件,项目中会多出两个文件 config(脚手架等配置文件)和 scripts(运行环境的配置)
npm安装失败解决
- 切换npm镜像为淘宝镜像
- 使用yarn,如果本来使用yarn还要失败,还得把yarn的源切换到国内
- 如果还没有办法解决,请删除node_modules及package-lock.json然后重新执行npm install命令
- 再不能解决就删除node_modules及package-lock.json的同时清除npm缓存npm cache clean --force 之后再执行npm install 命令
项目文件分析
build
- 生产环境文件
public
-
静态资源文件
-
public>index.html
- #root–整个项目的容器
- 设置icon
-
public>manifest.json
- 一些背景颜色,图标大小,字体颜色等css样式的设置
config(从node_modules抽离时生成,不可逆)
- 脚手架等配置文件
scripts(从node_modules抽离时生成,不可逆)
- 运行环境的配置
src
- 项目开发目录
src>index.js
- 相当于webpack的入口文件
- 主要的功能
- 渲染app组件
- ReactDOM 把虚拟dom渲染成真实dom,并把真实dom插入到一个容器(dom标签)中
- ReactDOM.render(组件,document.getElementById(‘root’) (容器))
- 设置通用样式
- 渲染app组件
src>index.css
- 全局样式
src>app.js
- 引入react,样式(index.js),图片
- 函数式组件(无状态组件(PureComponent))
Function App() {//组件名
return (
组件(
组件名必须大写, 否则报错
jsx语法(使用jsx语法必须要引入react),
单大括号 { 函数表达式 },
根元素唯一,不渲染根元素使用Fragment嵌套
组件不需要注册,
注释:{ 多行注释 },注释也是js语法
)
)
}
//其他写法
const App = (props) => <h1>欢迎进入{props.name}的世界</h1>
使用:
1、
App({
name: 'react'
})//不符合jsx语法
2、
// React组件的调用方式
<App name="react" />,
- 类组件(class)
import React , { Component } from 'react'
class App extends Component{
//react之前 React.createClass
render(){
<Flagment>app</Flagment>
}
}
export default App
同一个js文件中class组件嵌套
原理:
被嵌套组件实例化,再在另一个组件中使用
/*const app = new App({
name: 'react'
}).render()*/
可以不写,可以直接写类名
无状态组件 vs class组件
- 函数式组件是直接调用(调用函数),类组件其实就是一个构造器,每次使用组件都相当于在实例化组件
- jsx语法中的回避,
组件可以写html,css和js
但会出现冲突
css的class会被识别为js中的关键字或保留字
解决:css的class=》className
css的value=》defaultValue - 导出组件(es6)
DOM编译
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
<div className='app' id='appRoot'>
<h1 className='title'>欢迎进入React的世界</h1>
<p>
React.js 是一个构建页面 UI 的库
</p>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
编译之后将得到这样的代码:
import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
render () {
return (
React.createElement(
"div",
{
className: 'app',
id: 'appRoot'
},
React.createElement(
"h1",
{ className: 'title' },
"欢迎进入React的世界"
),
React.createElement(
"p",
null,
"React.js 是一个构建页面 UI 的库"
)
)
)
}
}
ReactDOM.render(
React.createElement(App),
document.getElementById('root')
)
组件中的dom样式(4种,style,className,第三方插件classnames和css-in-js)
- 单标签在组件中需要加 /
行内样式(style 推荐)
const styleBox = { color : 'red' , fontSize : '14px' }//实例属性
render(){
const styleObj = { color : 'red' , fontSize : '14px' }
//注意这里的两个括号,第一个表示我们在要JSX里插入JS了,第二个是对象的括号
<p style = { { color : 'red' , fontSize : '14px' } } > Hello world </p>
<p style = { styleObj } > Hello world </p>
<p style = { this.styleBox } > Hello world </p>
}
className
className = "类型"
第三方插件classnames(常用于类名切换)
yarn classNames
import classnames from 'classnames'
const names = classnames({
//类名:布尔值
content:true
})
使用:
<p className = { names } ></p>
css-in-js (在js中写css样式,第三方包(styled-components))
样式组件
import styled from 'styled-components'
const Container = styled.div`
width : 200px ;
height : 300px ;
`
//会解析成div
使用: <Container></Container>//可以组件嵌套,组件内文字不会覆盖,自动取类名,推荐使用
组件的数据挂载方式
react中数据分为两个部分
- props 属性(一开始就具备的)
- state 状态(频繁变化的数据 )
属性(props)
- 外部传入
- 内部设置
在类组件中的使用
外部传入
<propsCom name = "zhangsan"></propsCom>
获取 this.props.属性名
默认属性设置设置
//class组件
static defaultProps = {//该定义为16版本以上
name : "lisi"
}
getDefaultProps(){//15版本用法,钩子函数
return {
name : "wangwu"
}
}
获取 this.props.属性名
//函数式组件
// 使用箭头函数创建的组件,需要在这个组件上直接写defaultProps属性
组件名.defaultProps = {
name: 'React.js'
}
在函数式组件中使用
外部传入
const item = ( props ) => {
return (
<div>
{ props } //props为外部传入的值
</div>
)
}
-props.children //获取父组件中放在子组件中的值
子组件:
const Content = ( props ) => {
return (
<p> { props.children }</p>
)
}
props属性验证(prop-types第三方插件)
npm i prop-types -S
import React from 'react'
import PropTypes from 'prop-types'
class MyComponent extends React.Component{
render() {
}
}
MyComponent.propTypes = {
//属性名:数据类型
optionalArray:PropTypes.array/bool/func/number/object/string/symbol/node/element
}
props.children
props.children类似于vuejs中的插槽
<Content><i>React.js</i>是一个构建UI的库</Content>
上面的代码中,组件Content中的html内容其实也是一个组件(静态的)
一般在使用不会显示,这是因为没有在Content中渲染,可以通过props.children来获取到这个组件,并通过jsx语法使用
const Content = (props) => {
return (
<p>{props.children}</p>
)
}
状态(state)
- 组件自己的状态只能自己更改
class App extends Component {
//第一种形式
state = {
price:1000
}
render(){
return (
{ this.state.price }
)
}
}
第二种形式(推荐),与第一种形式不能一起使用
class App extends Component {
constructor(){
super()//修正this指向,让App继承Component
this.state = {
name : 'zhangsan'
}
}
render(){
return {
{ this.state.name }
}
}
}
数据修改
this.props和this.state是纯js对象,在vue中,data属性是利用Object.defineProperty处理过的,更改data的数据的时候会触发数据的getter和setter,但react没有做这样的处理,需要通过使用特殊的更改状态的方法setState
change () {
this.setState({
name:“lisi"
})
}//使用这种写法时在render函数中使用时是this.setState,会出现this丢失,需要写成this.setState.bind(this)
或者把使用setState方法的函改成箭头函数
change = () => {
this.setState ({
name:"wangwu"
})
}
或
change = () => {
this.setState( ()=> {
修改操作//数据修改了,但视图未更新
return {//再次覆盖,为了触发视图更新
name: this.state.name
}
})
}
setState参数
- setState函数是异步的
- 第一个参数可以是对象,也可以是方法**(return 一个对象,它有两个参数,第一个参数表示改变之前的state,第二个参数是this上的属性(props))**
- 第二个参数是一个回调函数
属性vs状态
相似点
- 是纯js对象,都会触发render更新,都具有 确定性(状态/属性相同,结果相同)
不同点
1.属性能从父组件获取,状态不能
2.属性可以有父组件修改,状态不能
3.属性能在内部设置默认值,状态也可以
4.属性不在组件内部修改,状态要改
5.属性能设置子组件初始值,状态不可以
6.属性可以修改子组件的值,状态不可以
- 没有state的组件叫做无状态组件,有state的组件叫做有状态组件
属性与状态总结
state
的主要作用是用于组件保存、控制、修改自己的可变状态。state
在组件内部初始化,可以被组件自身修改,而外部不能访问也不能修改。你可以认为 state
是一个局部的、只能被组件自身控制的数据源。state
中状态可以通过 this.setState
方法进行更新,setState
会导致组件的重新渲染。
props
的主要作用是让使用该组件的父组件可以传入参数来配置该组件。它是外部传进来的配置参数,组件内部无法控制也无法修改。除非外部组件主动传入新的 props
,否则组件的 props
永远保持不变。
如果搞不清 state
和 props
的使用场景,记住一个简单的规则:尽量少地用 state
,多用 props
。
没有 state
的组件叫无状态组件(stateless component),设置了 state 的叫做有状态组件(stateful component)。因为状态会带来管理的复杂性,我们尽量多地写无状态组件,尽量少地写有状态的组件。这样会降低代码维护的难度,也会在一定程度上增强组件的可复用性。
个人见解
- state在组件传递的时候,因为state和props都用this.props接收,所以state不可能出现在子组件中(转变成了属性),当this.props接收的是一个函数时,可以在组件中定义箭头函数,在内部不修改函数指向的情况下运行
- 父组件通过ref获取子组件数据时,要把state修改的逻辑在子组件中写成函数,才能在父组件中不修改this的情况下实现state的修改
- 在以函数的创建组件的时候,函数的参数为props,所以可以用es6解构
状态提升
如果有多个组件共享一个数据,把这个数据放到共同的父级组件中来管理
受控组件与非受控组件
react组件的数据渲染是否被调用,是通过传递过来的props完全控制,控制则为受控组件,否则非受控组件
(就是父组件传值给子组件,子组件中使用三元表达式之类的方法控制内容的显示)
渲染数据
- 条件渲染
{ condition ? 'A' : 'B'}
{ condition && 'A' || 'S' }
- 列表渲染
方法1 初级写法
this.state.name.map(( item,index ) => {
return (
{ item.firname }
)
}
)
方法二 推荐 组件拆分
const Item = ( prop ) => {
return <p>{ prop.name.firname } </p>
}
class
render () {
return (
<div>
{
this.state.name.map(( item,index ) => <Item item = { item } key = { item.id } ></Item>
)}</div>)}
第三种 更进一步的组件拆分
const Item = ( prop ) => {
return <p>{ prop.name.firname } </p>
}
class
renderItem = ( ) => {
return this.state.name.map(( item,index ) => <Item item = { Item } ></item>
)}
render () {
return (
<div>
{ this.renderItem() }
</div>
)
}
}
数据中的html标签转义(富文本)
dangerouslySetInnerHTML = {{ __html:this.state.content }} 在属性中使用
this.state.content为有html标签的文本(不使用富文本编辑,标签会被转义)
reactjs笔记至1100