I began to learn JavaScript and React these days, I tried to draw some grids in a website and met a problem like this:
Everything works fine when I code like this:
export default class PathfindingVisualizer extends Component {
constructor(props) {
super(props);
this.state = {
nodes: [],
};
}
componentDidMount() {
const nodes = getInitialGrid();
this.setState({ nodes });
}
render() {
const { nodes } = this.state;
console.log(nodes);
return (
<>
<p style={{ fontSize: 40 }}>Visualize Algorithms</p>
<br />
<br />
<div className="node-container">{nodes}</div> // HERE WORKS FINE
</>
);
}
}
And the website turned out to be like this which is fine:
But when I changed the code like this:
render() {
const { nodes } = this.state;
console.log(nodes);
return (
<>
<p style={{ fontSize: 40 }}>Visualize Algorithms</p>
<br />
<br />
<NodeContainer>{nodes}</NodeContainer> // HERE
</>
);
}
}
The grids just disappear, and nothing in <body>:
Could anybody help me? I can't figure out why this is happening.
Class NodeContainer and Node are like this:
export default class NodeContainer extends Component {
render() {
return <div className="node-container"></div>;
}
}
export default class Node extends Component {
render() {
return <div className="node-item"></div>;
}
}
Hey, thank you guys for the answers:) this is my first time to ask a question here. I solved the problem by adding {this.props.xxxxx} as you said and it works.
Corrected codes as following:
...
<br />
<br />
<NodeContainer nodes={nodes}></NodeContainer> // HERE
</>
...
the NodeContainer class:
export default class NodeContainer extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return <div className="node-container">{this.props.nodes}</div>; //HERE
}
}
I didn't use 'this.props.children', but will check out later. I skipped the basic tutorial so I didn't understand how to pass params to class, I checked this video to help myself quickly understand this:
https://www.youtube.com/watch?v=ICmMVfKjEuo&list=PLN3n1USn4xlntqksY83W3997mmQPrUmqM&index=5&t=0s
For this you need to call children inprops
export default class NodeContainer extends Component {
render() {
return <div className="node-container">{this.props.children}</div>;
}
}
I don't see where the Node class is being referenced so I'm not sure that's relevant.
Your issue is that the your passing the nodes component to the NodeContainer component, but not rendering it in NodeContainer. You should look into how props are passed to components - they appear as this.props.children on the component. Your code should look like this.
export default class NodeContainer extends Component {
render() {
return <div className="node-container">{this.props.children}</div>;
}
}
If you're wondering how nodes appears as this.props.children, it's because of how React treats components. You can achieve the same thing by passing it into children explicitly as a prop.
Dude, in reactJS, there's should be data to be pass from your Parent element to your Children element.
In your case to be able to show the data you want,
you need to pass your state from the <PathFindingVisualizer /> to your <NodeContainer />, which you have done it by using node as a children between <NodeContainer /> tag. And you forget the second step,
You need to access the data you have passed inside <NodeContainer /> class you made. How? just access it by using this.props.children.
here's the example.
export default class NodeContainer extends Component {
render() {
return <div className="node-container">{this.props.children}</div>
}
}
Problem solved.
as a reference see this. https://learn.co/lessons/react-this-props-children
Related
I have two files First.js and Second.js they are not child and Parent they have a lot of functions inside them. I want to use 1 function which is inside First.js into another file Second.js.
First.js
export default Header extends React.Component{
constructor(){
super();
}
updateXS(e){
alert('Test');
}
}
Second.js
export default Second extends React.Component{
constructor(){
super();
}
solveVariable() {
updateXS()// from first file
}
render(){
return (
<div className="displayinline col-md-12 ">
<button onClick={self.solveVariable.bind(this)}>Solve</button>
</div>
);
}
}
On click of Solve button in need to call updateXS() there are other functions render() also present in the first file.
You need to bubble up the action to a container
export default Second extends React.Component{
constructor(){
super();
}
solveVariable() {
this.props.handleSolveVariable();
}
render(){
return (
<div className="displayinline col-md-12 ">
<button onClick={self.solveVariable.bind(this)}>Solve</button>
</div>
);
}
}
Then the container can handle the solving part, set a state and pass it to the children.
class Container extends Component {
solveThis(e) {
// ... calculate
return result;
}
handleSolveVariable = (e) => {
const result = this.solveThis(e);
this.setState({result})
}
render() {
return (
<div>
<First result={this.state.result}/>
<Second result={this.state.result} handleSolveVariable={this.handleSolveVariable}/>
</div>
);
}
}
You should keep in mind the «actions up, data down» philosophy of react and not rely on observing events like in Jquery.
The children can react based on the new state an rerender.
You can also use componentWillReceiveProps to compare new props and react to it.
You can bubble up or create an utils function file and then export them. If you think is a function that you might use across your application it might be the best solution.
I'm developing a more complex example of passing props from a component to another. In this case, it's the content of an array(when I click on that content) to a <div>.
You can find the code here: https://codesandbox.io/s/509j5npkwx
(Please check the code in the link above)
TextBox <div> component:
export class TextBox extends React.Component {
constructor(props) {
super(props);
this.state = {
content: "Select A Node To See Its Data Structure Here..."
};
this.changeContent = this.changeContent.bind(this);
}
changeContent(newContent) {
this.setState({
content: newContent
});
}
render() {
return (
<div className="padd_top">
<div className="content_box">{this.state.content}</div>
</div>
);
}
}
export default TextBox;
FileTree component:
export class FileTree extends React.Component {
constructor(props) {
super(props)
this.state = {
activeNode: null
}
this.setActiveNode = this.setActiveNode.bind(this)
}
setActiveNode(name) {
this.setState({ activeNode: name })
}
render() {
return (
<div className="padd_top">{
renderTree(
this.props.root || root,
this.setActiveNode,
this.state.activeNode
)
}
<TextBox />
</div>
)
}
}
I'm trying to do something like this, for further understanding: http://alexcurtis.github.io/react-treebeard/
I understood how to prepare the <div> to receive new information, by substituting the "Select A Node To See Its Data Structure Here..." when I click one of the elements belonging to the file tree.
I also understood how to prepare the file tree to pass content <div>, but in this case, I'm confused about where and how should I apply to the right component.
I'm new to React JS. If you have any tips for me about this issue, I'm very grateful.
Thank you.
I changed a bit the structure of my project, and now I'm looking forward to put <TextBox> and <FileTree> side by side.
More specifically, like this:
export class App extends React.Component {
render() {
return (
<div>
<div className="col-md-12">
<SearchEngine />
</div>
<div className="col-md-6">
<FileTree />
</div>
<div className="col-md-6">
<TextBox content={this.props.activeNode} />
</div>
</div>
);
}
}
I tought it wouldn't be different to pass props to <App>, but again I might be missing something, because it's not passing properly. What is missing here?
Thanks again.
I'm not sure if I understood your question.
Here is my fork: https://codesandbox.io/s/50pv75q8ll
Basically, you pass the activeNode to < TextBox />. Look at line 126 of index.js.
And then, in text_box.js use componentWillReceiveProps() to set the TextBox state with the content prop. Line 18 of text_box.js.
I have a dumb component, List, that has some methods defined like this:
class List extends React.Component {
...
scrollTo() {
...
}
clear() {
...
}
}
I then use it in a Parent Component, let's say UsersList:
class UsersList extends React.Component {
render() {
return <List {...this.props} {...} />;
}
}
Then I have as a Parent I have FriendsPage:
class FriendsPage extends React.Component {
render() {
return (
...
<UsersList ref={(ref) => { this.usersListRef = ref; }} {...} />
);
}
}
I'd like to be able to call this.usersListRef.scrollTo() for example in FriendsPage, without having to define the methods of List in UsersList.
I can pass a prop called listRef and use it as ref={this.props.listRef} but I was wondering if another solution exists.
You can't call functions of a child and that would also be against the idea of react. Ideally your <UserList> component accepts a prop that makes it know where to scroll to. Something like:
class UserList extends React.Component {
componentDidUpdate() {
const {activeItem} = this.props;
this.scrollTo(activeItem);
}
scrollTo = activeItem => {
// calculate position of active item to scroll to
// and scroll to it
}
}
And then your <FriendsPage> could look something like this:
class FriendsPage extends React.Component {
handleSelectionChange = selected => {
// triggered when the selected element in the list changes
this.setState({selected});
}
render() {
const {selected} = this.state;
return <UserList activeItem={selected} {...this.props} />;
}
}
It's hard to tell if this is 100% the approach you need as you did not provide many details about the conditions that lead to scrolling.
Mmmm, I'm not sure if I'm getting It right, but you should read this: https://reactjs.org/docs/thinking-in-react.html
In React, the idea is to go top-down. As you need the UsersList component to do something when user interacts with List component, then you should define the function in UsersList and pass that function as a prop to the List Component.
For example:
class List extends React.Component {
<div onClick={this.props.scrollTo}
}
I then use it in a Parent Component, let's say UsersList:
class UsersList extends React.Component {
scrollTo(){
do something...
}
render() {
return <List scrollTo={() => this.scrollTo()} {...this.props} {...} />;
}
}
Then I have as a Parent I have FriendsPage:
class FriendsPage extends React.Component {
render() {
return (
...
<UsersList {...} />
);
}
}
I forgot to check the documentation on this one, and there is a paragraph about it here: https://reactjs.org/docs/refs-and-the-dom.html#exposing-dom-refs-to-parent-components.
Basically, it is the solution I envisaged in my question, using a listRef and passing it down to wherever my List Component is.
Thanks, everyone!
I have a react component, let's call him ReactContainer.
ReactContainer contains a few elements which one of them is MyReactBox and one of them is ReactInnerContainer (a code example is below).
My problem is that if a put an element inside ReactInnerContainer into fullscreen using the requestFullScreen API, then it overrides on MyReactBox, although MyReactBox has the CSS zIndex property to the maximum value possible.
export default class ReactContainer extends React.Component {
render() {
return (
<div>
<MyReactBox />
<br />
<ReactInnerContainer />
</div>
);
}
}
export default class ReactInnerContainer extends React.Component {
handleFullScreenClick() {
this.refs.innerDiv.webkitRequestFullscreen();
}
render() {
return (
<div ref="innerDiv">
/* Some stuff here */
</div>
);
}
}
I wish that although innerDiv is in fullscreen, MyReactBox will still be shown on the front of the screen. If I render MyReactBox inside innerDiv then it works, but I need MyReactBox to be rendered in ReactContainer.
Any ideas how to solve the problem?
Thanks a lot :)
Call webkitRequestFullscreen on the parent component
export default class ReactContainer extends React.Component {
handleFullScreen (){
this.screen.webkitRequestFullscreen();
}
render() {
return (
<div ref={(screen) => {this.screen = screen }}>
<MyReactBox />
<br />
<ReactInnerContainer handleFullScreen={this.handleFullScreen.bind(this)}/>
</div>
);
}
}
export default class ReactInnerContainer extends React.Component {
handleFullScreenClick() {
this.props.handleFullScreen();
}
render() {
return (
<div >
/* Some stuff here */
</div>
);
}
}
I am trying to set the contents of a component <ParentComponent/> dynamically by appending various child components <ChildComponen1/>, <ChildComponen3/>, <ChildComponen3/> according to the props values passed to the <ParentComponent/>. The parent component is a list and the child components are list items with varying content (css, html)
Below I have detailed an approach that I think would be appropriate for the situation however If you have an alternative (more efficient) method of achieving the specified goal of dynamically populating a parent component with various different child components, your insight would be most appreciated.
Thanks
class ParentComponent extends React.Component{
render(){
return(
<ComponentSwitch type="ChildComponen1"/>
<ComponentSwitch type="ChildComponen2"/>
)
}
}
class ComponentSwitch extends React.Component{
render(){
return(
//How would I most effectively create a switch here?
)
}
}
...child components omitted for brevity
What would be the most effective and efficient way to achieve this function?
Thanks
Just write some Javascript...
Many possibilities here, for example:
class ComponentSwitch extends React.Component {
renderA() {
return (
<div>
... lot of child components here
</div>
);
}
render() {
if (this.props.a) {
return this.renderA();
}
return <B />;
}
}
Or use switch statement and return component to render. Whatever you do
class ComponentSwitch extends React.Component {
render() {
switch (this.props.component) {
case 'a':
return <A />;
case 'b':
return <B />;
default:
return <C />;
}
}
}
Do whatever JS allows you to do :)
I'll answer the issue I understood, that I'm not sure is your real problem but here it goes.
First make your type parameter as the real Class you want it to be represented by.
import ChildComponent1 from './ChildComponent1.jsx';
import ChildComponent2 from './ChildComponent2.jsx';
class ParentComponent extends React.Component{
render(){
return(
<ComponentSwitch type={ChildComponen1} name='John'/>
<ComponentSwitch type={ChildComponen2} name='Doe'/>
)
}
}
Then extract the type from the props, and pass the rest of the props for the child Component.
class ComponentSwitch extends React.Component{
render(){
const {
type: Component,
...props,
} = this.props;
// props will now have 'name' and other props ready for the child component
return <Component {...props} />;
}
}