Internship Xiao Bai really wrote the front end for the first time, used React for the first time, took notes while writing the project, and used the components of SAP UI5 in the final code. Forgive me that direct copy does not work.
Also, I can't show highlights here directly in jsx format, so I use js format directly
1. Basic Structure
We want to build a searchable sidebar like the one shown, and enter keywords in search to filter the data shown below
We can define a LeftSide component that contains MySearchInput and MySideNav components to receive input and display keyword filtered data, respectively
2. Preparatory knowledge
We need prep-knowledge of local data and data transfer between components in react
1. Fetch for data reading
First we get the json data locally, rather than using jQuery with React, we get the data locally or remotely using the encapsulated fetch function, with the following code
fetch( './data/XXX/XXX.json' ) .then(res => res.json()) .then(data => { console.log(data) }) .catch(e => console.log('error:', e))
The only thing worth noting here is that. /denotes the public/directory, which is the directory where index.hml is located
Note the difference from the import path in the js file, where. /represents src/directory
2. props and state for data transfer
The main components responsible for data transfer are props and state.
props
We can think of props as a const parameter passed into a function.
function Component(props) { return <h1>I have a prop1: {props.prop1}!</h1>; } const element = <Component name="c1" prop1="propValue"/>;
As an example, we pass in two values, c1 and propValue, to a Component in which we can access these two values using this.props.name and this.props.prop1, which we call the properties of a Component Component (props)
function access without adding this
It is worth noting that props cannot be changed in components, that is, even if you change it, it will have no effect (unless)
More props operations are detailed in -props property of React series
state
Contrasting props, we can think of a state as a variable in a class (different from the normal class variable this.a).
class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date(), a:10, b:this.props.b }; } render() { return ( <div> <h1>Hello, world!</h1> <h2>Now is {this.state.date.toLocaleTimeString()}.</h2> <h3> {this.state.a} </h3> </div> ); } }
As an example, we created a state called date in the constructor and accessed it using this.state.date (where the date state is a class and not simple data)
State differs from props in more than just the way it is initialized. When we use **this.setState to modify the state in a component, it will automatically re-render **
this.setState({a:this.state.a+1});
If you execute the above code, the 10 displayed on the web page will become 11
Note that the constructor of a class is called only at creation time, and that this.state.b, which is assigned only in the constructor, remains unchanged when the parent passes in this.props.b changes
See in detail Props for React and the difference from state
Props for React and the difference from state It is mentioned in the article that stateless components (i.e. components without states) should be used whenever possible instead of stateful components
Downward Flow Data and State Promotion
From the description above, we know that props can only be passed in by parent to child components, so it is called downflow data, and state can only record state in the current component
Direct use of props and States does not seem to complete data transfer between child and parent or sibling components.
But with callback functions, we can do this in a way called state elevation
For example, we have a parent component, Base, and a child component, Child. We get data from Child by user input. Our goal is to pass data into Base
First we set the state this.state.data (not required) and a function handleData (required) to modify/pass the data in Base, and pass the handleData function to Child through props. When Child gets the data, the handleData function of the parent component is called through certain events (such as clicking on the onClick event)., successfully passed data to Base
In Child, we can also set a class variable or state to store data for convenient function calls. If the subcomponents get data through the input component, we can also process e.target.value directly with E as a parameter.
Function arguments require a.bind(this, parameter) way of binding, as detailed in How the onClick function of React passes parameters We can also set up another jumper function in our component, handleData, to call handleData directly in _handleData
Introduction to Official Website
React Learning: Example of State Promotion
3. refs for data transfer
I have not tested this way
If you find the above state improvement more difficult, we can use another new concept, refs
Refs can be used to access Dom nodes in render() (React does not recommend getting DOM nodes directly from document.getElementById("xxx"), which is commonly used in control input/video/audio scenarios (but be careful not to abuse refs)
There are three ways to use refs, and here we will only describe one of them, React.createRef(), and the other two are detailed in Summary React(3):state, props, Refs
After v16.3, we can use React.createRef() to create a series of refs for the parent component, get the child component in render() in a similar way to assigning attributes, and then access it in the parent component. The sample code is as follows
import React from 'react'; class TextInput extends React.Component { constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); // Create Refs through React.createRef(); this.textInput = React.createRef(); } handleClick() { // Access Dom nodes through this.textInput.current this.textInput.current.focus(); console.log(this.textInput.current.value) } render() { return ( <div> <input type="text" ref={this.textInput} /> <input type="button" value="Click on my input box to get focus" onClick={this.handleClick} /> </div> ); } } export default TextInput;
3. Specific Codes
!! I use sap ui5 Part of the components in the, do not affect reading, when you use the corresponding components directly replace the line
LeftSide
Parent component, where this.props._handleClick is the parent component of LeftSide used to handle clicks in the list, ignored here
class LeftSide extends React.Component { constructor(props) { super(props); this.version = props.version; this.state = { search_key: "" } } handleInput(e) { console.log(e.target.value) this.setState({ search_key: e.target.value }) } render() { return ( <div className='leftPage' > <div className='searchInput'><MySearchInput changeInput={(e) => this.handleInput(e)} /></div> <div className='sideNav'><MySideNav searchKey={this.state.search_key} _handleClick={this.props._handleClick} /></div> </div> ) } shouldComponentUpdate() { return true; } }
MySearchInput
Processing user input, changing the data transfer to the parent component in real time (we can also use _onSearch to transfer on click)
class MySearchInput extends React.Component { constructor(props) { super(props); this._onChange = props.changeInput; this.state = { key: "" } } _onSearch(evt) { console.log("Final:") console.log(this.props.value) } render() { let _onChange = this.props.changeInput; return ( <FormItem> <InputGroup actions inputValue={this.state.value} onChange={_onChange} > <Button glyph="search" option="light" onClick={this._onSearch.bind(this)} /> </InputGroup> </FormItem> ) } }
MySideNav
Implement real-time search (output when searchKey is empty or matches)
class MySideNav extends React.Component { constructor(props) { super(props); this.cate_map = { "Type1": { "items": [[]] } } //json data structure this.loadJson(); //Loading data console.log("sonstructor done") } loadJson() { let cate_path = './data.json'; fetch( cate_path ) .then(res => res.json()) .then(data => { console.log("from loadJson") this.cate_map = data; //Direct assignment }) .catch(e => console.log('error:', e)) this.setState({ update:"" })//Because of asynchronous, re-rendering is required after loading is complete } handleClick(keywordID) { console.log("from handleClick") console.log(keywordID) this.props._handleClick(keywordID) //Processing list clicks, ignored here } render() { console.log("render") console.log("log from NAVI") console.log(this.props.searchKey) let ct_list = this.cate_map.ComplexType let complexType_list = []; for (let index in ct_list.items) { let itemName = ct_list.items[index][1]; if (this.props.searchKey == "" || itemName.indexOf(this.props.searchKey) != -1) complexType_list.push(<SideNav.ListItem id={ct_list.items[index][0]} name={itemName} onClick={this.handleClick.bind(this, ct_list.items[index][0])} url="#" />) } return ( <SideNav selectedID="SideNav"> <SideNav.List> <SideNav.ListItem id="Type1" name="Type1" url="#"> <SideNav.List> {complexType_list} </SideNav.List> </SideNav.ListItem> </SideNav.List> </SideNav> ) } }