ref是一个函数又有什么好处?
- 方便react销毁组件、重新渲染的时候去清空refs的东西,防止内存泄露
解释 React 中 render() 的目的。
每个React组件强制要求必须有一个 render()。它返回一个 React 元素,是原生 DOM 组件的表示。如果需要渲染多个 HTML 元素,则必须将它们组合在一个封闭标记内,例如 <form>
、<group>
、<div>
等。此函数必须保持纯净,即必须每次调用时都返回相同的结果。
什么是JSX
jsx 是 JavaScriptXML的简写,是react使用的一种文件,它利用 JavaScript 的表现力和类似 HTML 的模板语法,这使得 HTML 文件非常容易理解。此文件能使应用非常可靠,并能够提高其性能
jsx的语法规则
- 定义虚拟DOM的时候 不需要写引号
- 标签中要混入js表达式的时候需要用 {}
- 在jsx中写标签的类名的时候 用className 代替class
- 内联样式的时候 ,需要style={{key:value}}
- 标签必须要闭合
- 标签首字母的约定
若为小写字母,则将jsx转换为html中同名元素,若html中无该标签明对应的同名元素 则报错
若为大写字母,react就去渲染对应的组件,若没有定义组件 则报错
- 当根据数据遍历生成的标签,一定要给标签设置单独的key 否则会报错
React 中 keys 的作用是什么?
Keys
是React
用于追踪哪些列表中元素被修改、被添加或者被移除的辅助标识
- 在开发过程中,我们需要保证某个元素的
key
在其同级元素中具有唯一性。在React Diff
算法中React
会借助元素的Key
值来判断该元素是新近创建的还是被移动而来的元素,从而减少不必要的元素重渲染。此外,React 还需要借助Key
值来判断元素与本地状态的关联关系,因此我们绝不可忽视转换函数中Key
的重要性
react 实现一个全局的 dialog
代码语言:javascript复制import React, { Component } from 'react';
import { is, fromJS } from 'immutable';
import ReactDOM from 'react-dom';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import './dialog.css';
let defaultState = {
alertStatus:false,
alertTip:"提示",
closeDialog:function(){},
childs:''
}
class Dialog extends Component{
state = {
...defaultState
};
// css动画组件设置为目标组件
FirstChild = props => {
const childrenArray = React.Children.toArray(props.children);
return childrenArray[0] || null;
}
//打开弹窗
open =(options)=>{
options = options || {};
options.alertStatus = true;
var props = options.props || {};
var childs = this.renderChildren(props,options.childrens) || '';
console.log(childs);
this.setState({
...defaultState,
...options,
childs
})
}
//关闭弹窗
close(){
this.state.closeDialog();
this.setState({
...defaultState
})
}
renderChildren(props,childrens) {
//遍历所有子组件
var childs = [];
childrens = childrens || [];
var ps = {
...props, //给子组件绑定props
_close:this.close //给子组件也绑定一个关闭弹窗的事件
};
childrens.forEach((currentItem,index) => {
childs.push(React.createElement(
currentItem,
{
...ps,
key:index
}
));
})
return childs;
}
shouldComponentUpdate(nextProps, nextState){
return !is(fromJS(this.props), fromJS(nextProps)) || !is(fromJS(this.state), fromJS(nextState))
}
render(){
return (
<ReactCSSTransitionGroup
component={this.FirstChild}
transitionName='hide'
transitionEnterTimeout={300}
transitionLeaveTimeout={300}>
<div className="dialog-con" style={this.state.alertStatus? {display:'block'}:{display:'none'}}>
{this.state.childs} </div>
</ReactCSSTransitionGroup>
);
}
}
let div = document.createElement('div');
let props = {
};
document.body.appendChild(div);
let Box = ReactD
子类:
代码语言:javascript复制//子类jsx
import React, { Component } from 'react';
class Child extends Component {
constructor(props){
super(props);
this.state = {date: new Date()};
}
showValue=()=>{
this.props.showValue && this.props.showValue()
}
render() {
return (
<div className="Child">
<div className="content">
Child <button onClick={this.showValue}>调用父的方法</button>
</div>
</div>
);
}
}
export default Child;
css:
代码语言:css复制.dialog-con{
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
}
概述一下 React中的事件处理逻辑。
为了解决跨浏览器兼容性问题, React会将浏览器原生事件( Browser Native Event)封装为合成事件( Synthetic Event)并传入设置的事件处理程序中。
这里的合成事件提供了与原生事件相同的接口,不过它们屏蔽了底层浏览器的细节差异,保证了行为的一致性。另外, React并没有直接将事件附着到子元素上,而是以单一事件监听器的方式将所有的事件发送到顶层进行处理(基于事件委托原理)。
这样 React在更新DOM时就不需要考虑如何处理附着在DOM上的事件监听器,最终达到优化性能的目的。
传入 setstate函数的第二个参数的作用是什么?
第二个参数是一个函数,该函数会在 setState函数调用完成并且组件开始重渲染时调用,可以用该函数来监听渲染是否完成。
代码语言:javascript复制this.setstate(
{
username: "有课前端网",
},
() => console.log("re-rendered success. ")
);
refs的作用是什么,你在什么样的业务场景下使用refs
- 操作DOM,为什么操作DOM?
- 场景
- 图片渲染好后,操作图片宽高。比如做个放大镜功能
(组件的)状态(state)和属性(props)之间有何不同
State
是一种数据结构,用于组件挂载时所需数据的默认值。State
可能会随着时间的推移而发生突变,但多数时候是作为用户事件行为的结果。
Props
(properties 的简写)则是组件的配置。props
由父组件传递给子组件,并且就子组件而言,props
是不可变的(immutable)。组件不能改变自身的 props,但是可以把其子组件的 props 放在一起(统一管理)。Props 也不仅仅是数据--回调函数也可以通过 props 传递。
什么是上下文Context
Context 通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。
- 用法:在父组件上定义getChildContext方法,返回一个对象,然后它的子组件就可以通过this.context属性来获取
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class Header extends Component{
render() {
return (
<div>
<Title/>
</div>
)
}
}
class Title extends Component{
static contextTypes={
color:PropTypes.string
}
render() {
return (
<div style={{color:this.context.color}}>
Title
</div>
)
}
}
class Main extends Component{
render() {
return (
<div>
<Content>
</Content>
</div>
)
}
}
class Content extends Component{
static contextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
render() {
return (
<div style={{color:this.context.color}}>
Content
<button onClick={()=>this.context.changeColor('green')}>绿色</button>
<button onClick={()=>this.context.changeColor('orange')}>橙色</button>
</div>
)
}
}
class Page extends Component{
constructor() {
super();
this.state={color:'red'};
}
static childContextTypes={
color: PropTypes.string,
changeColor:PropTypes.func
}
getChildContext() {
return {
color: this.state.color,
changeColor:(color)=>{
this.setState({color})
}
}
}
render() {
return (
<div>
<Header/>
<Main/>
</div>
)
}
}
ReactDOM.render(<Page/>,document.querySelector('#root'));
react有什么优点
- 提高应用性能
- 可以方便的在客户端和服务端使用
- 使用jsx模板进行数据渲染,可读性好
react中key的作用
简单的说:key 是虚拟DOM中的一种标识,在更新显示是key起到了极其重要的作用
复杂的说:当状态中的数据发生改变的时候,react会根据【新数据】生成【新的虚拟DOM】,随后react进行【新虚拟DOM】 和 【旧的虚拟DOM】的diff比较,而在这个比较过程中key就是起到是关键中用
与 ES5 相比,React 的 ES6 语法有何不同
以下语法是 ES5 与 ES6 中的区别:
- require 与 import
// ES5
var React = require('react');
// ES6
import React from 'react';
- export 与 exports
// ES5
module.exports = Component;
// ES6
export default Component;
- component 和 function
// ES5
var MyComponent = React.createClass({
render: function() {
return
<h3>Hello Edureka!</h3>;
}
});
// ES6
class MyComponent extends React.Component {
render() {
return
<h3>Hello Edureka!</h3>;
}
}
- props
// ES5
var App = React.createClass({
propTypes: { name: React.PropTypes.string },
render: function() {
return
<h3>Hello, {this.props.name}!</h3>;
}
});
// ES6
class App extends React.Component {
render() {
return
<h3>Hello, {this.props.name}!</h3>;
}
}
- state
// ES5
var App = React.createClass({
getInitialState: function() {
return { name: 'world' };
},
render: function() {
return
<h3>Hello, {this.state.name}!</h3>;
}
});
// ES6
class App extends React.Component {
constructor() {
super();
this.state = { name: 'world' };
}
render() {
return
<h3>Hello, {this.state.name}!</h3>;
}
}
组件之间传值
- 父组件给子组件传值
在父组件中用标签属性的=形式传值
在子组件中使用props来获取值
- 子组件给父组件传值
在组件中传递一个函数
在子组件中用props来获取传递的函数,然后执行该函数
在执行函数的时候把需要传递的值当成函数的实参进行传递
- 兄弟组件之间传值
利用父组件
先把数据通过 【子组件】===》【父组件】
然后在数据通过 【父组件】===〉【子组件】
消息订阅
使用PubSubJs插件
React Portal 有哪些使用场景
- 在以前, react 中所有的组件都会位于 #app 下,而使用 Portals 提供了一种脱离 #app 的组件
- 因此 Portals 适合脱离文档流(out of flow) 的组件,特别是 position: absolute 与 position: fixed的组件。比如模态框,通知,警告,goTop 等。
以下是官方一个模态框的示例,可以在以下地址中测试效果
代码语言:html复制<html>
<body>
<div id="app"></div>
<div id="modal"></div>
<div id="gotop"></div>
<div id="alert"></div>
</body>
</html>
代码语言:javascript复制const modalRoot = document.getElementById('modal');
class Modal extends React.Component {
constructor(props) {
super(props);
this.el = document.createElement('div');
}
componentDidMount() {
modalRoot.appendChild(this.el);
}
componentWillUnmount() {
modalRoot.removeChild(this.el);
}
render() {
return ReactDOM.createPortal(
this.props.children,
this.el,
);
}
}
React Hooks当中的useEffect是如何区分生命周期钩子的
代码语言:javascript复制useEffect可以看成是
componentDidMount
,componentDidUpdate
和componentWillUnmount
三者的结合。useEffect(callback, source)接收两个参数,调用方式如下
useEffect(() => {
console.log('mounted');
return () => {
console.log('willUnmount');
}
}, [source]);
生命周期函数的调用主要是通过第二个参数source来进行控制,有如下几种情况:
[source]
参数不传时,则每次都会优先调用上次保存的函数中返回的那个函数,然后再调用外部那个函数;[source]
参数传[]时,则外部的函数只会在初始化时调用一次,返回的那个函数也只会最终在组件卸载时调用一次;[source]
参数有值时,则只会监听到数组中的值发生变化后才优先调用返回的那个函数,再调用外部的函数。
React-Router如何获取URL的参数和历史对象?
(1)获取URL的参数
- get传值
路由配置还是普通的配置,如:'admin'
,传参方式如:'admin?id='1111''
。通过this.props.location.search
获取url获取到一个字符串'?id='1111'
可以用url,qs,querystring,浏览器提供的api URLSearchParams对象或者自己封装的方法去解析出id的值。
- 动态路由传值
路由需要配置成动态路由:如path='/admin/:id'
,传参方式,如'admin/111'
。通过this.props.match.params.id
取得url中的动态路由id部分的值,除此之外还可以通过useParams(Hooks)
来获取
- 通过query或state传值
传参方式如:在Link组件的to属性中可以传递对象{pathname:'/admin',query:'111',state:'111'};
。通过this.props.location.state
或this.props.location.query
来获取即可,传递的参数可以是对象、数组等,但是存在缺点就是只要刷新页面,参数就会丢失。
(2)获取历史对象
- 如果React >= 16.8 时可以使用 React Router中提供的Hooks
import { useHistory } from "react-router-dom";
let history = useHistory();
2.使用this.props.history获取历史对象
代码语言:javascript复制let history = this.props.history;
展示组件(Presentational component)和容器组件(Container component)之间有何不同
展示组件关心组件看起来是什么。展示专门通过 props 接受数据和回调,并且几乎不会有自身的状态,但当展示组件拥有自身的状态时,通常也只关心 UI 状态而不是数据的状态。
容器组件则更关心组件是如何运作的。容器组件会为展示组件或者其它容器组件提供数据和行为(behavior),它们会调用 Flux actions
,并将其作为回调提供给展示组件。容器组件经常是有状态的,因为它们是(其它组件的)数据源。
为什么使用jsx的组件中没有看到使用react却需要引入react?
本质上来说JSX是React.createElement(component, props, ...children)
方法的语法糖。在React 17之前,如果使用了JSX,其实就是在使用React, babel
会把组件转换为 CreateElement
形式。在React 17之后,就不再需要引入,因为 babel
已经可以帮我们自动引入react。
createElement过程
代码语言:javascript复制React.createElement(): 根据指定的第一个参数创建一个React元素
React.createElement(
type,
[props],
[...children]
)
- 第一个参数是必填,传入的是似HTML标签名称,eg: ul, li
- 第二个参数是选填,表示的是属性,eg: className
- 第三个参数是选填, 子节点,eg: 要显示的文本内容
//写法一:
var child1 = React.createElement('li', null, 'one');
var child2 = React.createElement('li', null, 'two');
var content = React.createElement('ul', { className: 'teststyle' }, child1, child2); // 第三个参数可以分开也可以写成一个数组
ReactDOM.render(
content,
document.getElementById('example')
);
//写法二:
var child1 = React.createElement('li', null, 'one');
var child2 = React.createElement('li', null, 'two');
var content = React.createElement('ul', { className: 'teststyle' }, [child1, child2]);
ReactDOM.render(
content,
document.getElementById('example')
);
componentWillReceiveProps调用时机
- 已经被废弃掉
- 当props改变的时候才调用,子组件第二次接收到props的时候