reacy初体验,总结记录
- 官网 https://zh-hans.reactjs.org/docs/introducing-jsx.html
安装react项目
- create-react-app是你开始构建一个全新单页应用的最好方式
1
2
3
4
5npm install create-react-app -g
create-react-app my-app
cd my-app
npm start文件结构介绍
1
2
3node_modules:非常大
public:入口文件
src:源码文件(index.js入口js文件 App.js第一个页面)刚下载的react src文件中只留index.js和App.js即可基础知识
- react是由React、ReactDOM两个库组成的 但是react是有很多库组成的(react全家桶)
- 引入组化的时候首字母必须大写
1
2
3
4
5
6import React from 'react';
import ReactDOM from 'react-dom';
// document.getElementById('root')获取要插入id为root的容器 root在public的index.html中
// jsx语法 JavaScript + XML语法(HTML)
ReactDOM.render(<h1>hellow React</h1>, document.getElementById('root'));
{}中的代码按照js的方式去解析 - ReactDOM.render是reactDom提供的渲染函数render
组件 setState更新状态 修改状态
- 组件的后缀可以js也可以是jsx
- this.state相当vue中的data 页面元素的改变使用state纪念性处理
- 当调用setState之后state状态会更新,还会再次调用render重新渲染
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Clock extends Component{
//声明状态
constructor(){
//自定义组件状态对象
//状态可以用来存放组件内部一些变化的值,状态只能由内部初始化,内部改变
super(props);
this.state = {time:new Date().toLocaleString()};//初始化状态对象
}
//生命周期函数 组件挂载完成
componentDidMount(){
console.log('组件挂载后');
window.setInterval(()=>{
//获取 this.state 中的状态 setState改变状态
//当调用setState之后状态会更新,还会再次调用render重新渲染
this.setState({time:new Date().toLocaleString()})
},1000)
}
//render方法指的是该组件如何渲染
// 一定要返回一个react元素并且只能返回一个react元素
render(){
return <h1>{this.state.time}</h1>
}
}
render(<Clock/>,document.querySelector('#root'))Cannot read proprrty setState of underfind
- 是因为声明方法的this指向问题 一般方法都要用箭头函数好避免出现错误
JSX 需要注意的地方
- style属性
- 在React中写行内样式时,要这样写,不能采用引号的书写方式
1
2
3
4
5React.render(
<div style={{color:'red'}}>
xxxxx
</div>
);react绑定事件传参与不传参的区别
- 传参的话要回调函数return返回 在点击的时候调用
- 不传参的写法是一开始就会调用的,如果传参就会报错
1
2
3
4
5
6
7
8
9
10
11<Button onClick={() => this.handleConfirm('confirm')}></Button>
<Button onClick={this.reactClick.bind(this)}></Button>
<Button onClick={this.handleConfirm}>Confirm</Button>
//需要bind绑定this
reactClick(){
}
//this.handleConfirm写法 或者this.handleConfirm.bind(this)
handleConfirm = ()=>{
}Props子组件更改父组件数据
子组件触发父组件方法以及传参更改父组件数据
- 父组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29export default class Todo extends React.Component{
constructor(props){//props父组件往子组件里传参用的在子组件里不能被改变
super(props);
//定义默认状态对象
this.state = {
todos:[
{id:Date.now(),title:'今天好好学习',completed:false},
]
}
}
addTodo = (todo)=>{
//接受子组件的参数 并合并对象
todo = Object.assign({},{id:Date.now(),completed:false},todo)
let todos = this.state.todos;
todos.push(todo);
//更改值必须setState
this.setState({todos})
}
render(){
return (
<div className="container" style={{marginTop:20}}>
<div className="row">
{/* 将方法作为属性传给子组件*/}
<TodoHeader addTodo={this.addTodo}></TodoHeader>
</div>
</div>
)
}
} - 子组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20export default class TodoHeader extends React.Component{
handleKeydown = (event)=>{
if(event.keyCode == EBTER_KEY){
let title = event.target.value
//props触发父组件方法并传递值
this.props.addTodo({title})
}
}
render(){
return (
<div>
<form>
<div onKeyDown={this.handleKeydown}>
<input autoFocus={true} type="text" />
</div>
</form>
</div>
)
}
}接收父组件数据
- data是父组件中的数据 自定义data的形式给子组件
- 子组件获取到父组件数据的方式{this.props.data}data跟父组件自定义的属性相同即可
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23export Father class TodoHeader extends React.Component{
constructor(){
super()
this.state = {name:'wanglei'}
}
render(){
return (
<div>
<Child data={this.state.name}/>
</div>
)
}
}
export Child class TodoHeader extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<div>{this.props.data}</div>
)
}
}兄弟之间传值
1
2
3
4
5
6
7
8
9
10
11
12
13
14export Father class TodoHeader extends React.Component{
constructor(){
super()
this.state = {name:'wanglei'}
}
render(){
return (
<div>
<Child1/>
<Child2/>
</div>
)
}
}将数据迭代循环
- vue的是v-for就可以但是react需要map去映射
1
2
3
4
5
6
7
8
9
10
11this.state = {
todos:[
{id:Date.now(),title:'今天好1好学习',completed:false},
{id:Date.now(),title:'今天学vue',completed:false}
]
}
<ul className="list-group">
{this.state.todos.map ( (tode,index)=>{
return <TodoItem key={index} todo={tode}></TodoItem>
})}
</ul>获取input输入的值
- 拿到input的value的三种方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27reg = (){
//获取指定input的值
console.log(this.refs.username.value);
console.log(this.password.value);
}
onValueChange(e){
//拿到input输入的值
this.setState({
age:e.target.value
})
}
render(){
return (
<ul>
<li>
<input ref='username' type="text"/>
</li>
<li>
<input ref={(element)=>{this.password=element}} type="text" />
</li>
<li>
<a onClick={this.reg} className="login_btn">注册</a>
<input onChange={(e)=>{this.onValueChange(e)}}>
</li>
</ul>
)
}组件组合方式
- 纯组件形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class App extends React.Component{
render(){
return (
<div>
<h1>App</h1>
//单纯组件
<Components/>
</div
)
}
}
ReactDom.render(
<App/>,
document.getElementByid('app')
) - 容器式组件形式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//子组件
class Title extends React.Component{
constructor(props){
super(props)
}
render(){
return (
<h1>{this.props.title}</h1>
)
}
}
//父组件
class App extends React.Component{
render(){
return (
<div>
<Title title='App'></Title>
<Components/>
</div
)
}
}假如super不是纯文本的变量了 是一些jsx的语法选择容器式组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27//子组件
class Title extends React.Component{
constructor(props){
super(props)
}
render(){
return (
//children表示由Title组件包裹起来的部分
<h1>{this.props.children}</h1>
)
}
}
//父组件
class App extends React.Component{
render(){
return (
<div>
//容器式组件形式
<Title>
<span>App</span>
<a>link<a/>
</Title>
<Components/>
</div
)
}
}React生命周期
- 生命周期节点 Mounting挂载阶段、Updating运行时阶段、Unmounting组件卸载阶段、
- Error Handling 错误处理(只处理在render的错误 逻辑的不行)
- 1-4挂载阶段 其余是组件运行时的钩子函数除了componentWillUnmount是组件卸载阶段
1 | class Counter extends React.Component{ |
- getDefaultProps
- getInitialState
- 如果父组件在组件挂在完成向子组件传递参数用componentDidMount生命周期函数会是undefined,打印不同组件的componentDidMount会发现是先执行的是子组件的componentDidMount然后才是父组件,这样拿不到父组件传的值(
*在父组件运行完才将虚拟dom准换成真正的dom 所以找不到父级的dom节点信息*
)需要使用componentWillReceiveProps生命周期函数ref操作dom
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26export default class refsAndDom extends React.Component{
constructor(){
super();
this.state = {
}
this.helloDiv = React.createRef();
}
componentDidMount() {
console.log('ref',this.helloDiv.current);
this.helloDiv.current.style.color = "blue";
//跟vue操作一样 但是官方上删除这种写法了
this.refs.dom.style.color = "#cccccc"
}
render(){
return(
<div>
<h3>7:refs操作dom</h3>
<div ref={this.helloDiv}>ref更改文字颜色</div>
<div ref="dom">ref更改文字颜色</div>
</div>
)
}
}受控组件
- 表单内的value值是通过state来管理的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20constructor(){
super()
this.state = {
username:'',
password:''
}
}
onInputChange(e){
let inputValeu = e.target.value
let inputName = e.target.name
this.setState({
[inputName]:inputValeu
})
}
render(){
return(
<input type='text' name='username' onChange={e=>this.onInputChange(e)}>
<input type='text' name='password' onChange={e=>this.onInputChange(e)}>
)
} - 有时候受控组件会很麻烦,因为需要为数据变化的每种方式写处理函数- 所以又有一种非受控组件
非受控组件
- 自己操作dom的形式处理 一般推荐受控组件 input特别多事件多推荐非受控组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27import React from "react";
export default class refForm extends React.Component{
constructor(){
super()
this.username = React.createRef();
}
handleSubmit = (event)=> {
alert('提交的名字:'+this.username.current.value);
event.preventDefault();
}
render(){
return(
<div>
<h3>8:表单(2)非受控组件:自己操作dom的形式处理</h3>
<label>
名字:
<input type="text" ref ={ this.username } />
</label>
<button onClick={this.handleSubmit}>提交</button>
<div>正常情况下推荐受控组件 如果input特别多事件特别多 推荐非受控组件</div>
</div>
)
}
}react请求跨域
- 在package.json添加 “proxy”:”http://localhost:4000"//就跨地址或者proxy:{}