React How to pass arguments to function - reactjs

Hi I found a question asking the same thing but they coded completely different using 'class name extends', I am just using 'function name'. I was wondering how I would I solve this problem or do I have to rewrite my program.
I have styles at the bottom I left off.
Window.js
import React from 'react';
import "../css/Start.css";
export default function Window(nuts) {
let ulList=[]
for (let i=0;i<nuts.file.length;i++) {
ulList.push(<li>
{
nuts.file[i]
}
</li>)
}
let imageList=[]
for (let i=0;i<nuts.image.length;i++) {
imageList.push(<img src={nuts.image[i]} alt={nuts.image[i]}/>)
}
return (
<div style={main}>
<p>{nuts.name}</p>
<p>{nuts.date}</p>
<p>{nuts.note}</p>
{ulList}
{imageList}
<button> Demo </button>
</div>
);
}
Project.js
import React from 'react';
import Background from '../images/projectbackground.jpg';
import "../css/Start.css";
import Window from './Window'
export default function Project() {
const files = ['f1','f2','f3']
const images = ['p1','p2','p3']
const nuts = {name:'phil',date:'2/2/16',note:'this is a note',file:files,image:images}
return (
<div style={main}>
<Window nuts={nuts}/>
<div style={footer}>
</div>
</div>
);
}

Your function component will get passed all the properties together in an object.
There are three changes you could make to have this work:
render <Window {...{nuts}} /> instead (not recommended but is an option)
change parameters to function Window(props) and all your other code to say props.nuts instead of just nuts
change parameters to function Window({nuts}) to destructure the (no longer named) "props" object

nuts is being passed to Window via the props object.
You either need to destructure nuts in-line or in your function body.
function Window({ nuts })
or
function Window(props) {
const { nuts } = props;
}

Related

Inject Props to React Component

For security reasons, I have to update ant design in my codebase from version 3 to 4.
Previously, this is how I use the icon:
import { Icon } from 'antd';
const Demo = () => (
<div>
<Icon type="smile" />
</div>
);
Since my codebase is relatively big and every single page use Icon, I made a global function getIcon(type) that returns <Icon type={type}>, and I just have to call it whenever I need an Icon.
But starting from antd 4, we have to import Icon we want to use like this:
import { SmileOutlined } from '#ant-design/icons';
const Demo = () => (
<div>
<SmileOutlined />
</div>
);
And yes! Now my getIcon() is not working, I can't pass the type parameter directly.
I tried to import every icon I need and put them inside an object, and call them when I need them. Here's the code:
import {
QuestionCircleTwoTone,
DeleteOutlined,
EditTwoTone
} from '#ant-design/icons';
let icons = {
'notFound': <QuestionCircleTwoTone/>,
'edit': <EditTwoTone/>,
'delete': <DeleteOutlined/>,
}
export const getIcon = (
someParam: any
) => {
let icon = icons[type] !== undefined ? icons[type] : icons['notFound'];
return (
icon
);
};
My problem is: I want to put someParam to the Icon Component, how can I do that?
Or, is there any proper solution to solve my problem?
Thanks~
You can pass props as follows in the icons Object:
let icons = {
'notFound':(props:any)=> <QuestionCircleTwoTone {...props}/>,
'edit': (props:any)=><EditTwoTone {...props}/>,
'delete':(props:any)=> <DeleteOutlined {...props}/>,
}
And then if you will pass any prop to the Icon component then it will pass the prop to the specific icon component
let Icon = icons[type] !== undefined ? icons[type] : icons['notFound'];
return (<Icon someParam={'c'}/>)

How to specify the type

I am learning typescript.
I used axios and stored the api return value in useEffect and displayed it on the screen, but I get an error saying that there is no name in the interface todoList.
What is the cause?
thank you.
import React, {useEffect, useState} from 'react';
import axios from 'axios';
interface todoList {
name: string
age: number
}
function App() {
const defaultProps: todoList[] = [];
const [todoList, setTodoList]: [todoList[], (todoList: todoList[]) => void] = useState(defaultProps);
useEffect(() => {
async function getTodo() {
const response = await axios.get('http://localhost/laravel/public/api/todo');
setTodoList(response.data);
}
getTodo();
}, []);
return (
<div className="App">
{todoList.name} // Error here.
</div>
);
}
export default App;
Point1: This is because UI gets rendered before useEffect and hence the moment UI gets rendered it looks for todolist.name where todolist is empty and fetching name throws error. If specific name of any items is to be displayed check the array length and name is not null before mapping to UI
Point2: If all the names is to placed in UI then map the array as below
import React, {useEffect, useState} from 'react';
import axios from 'axios';
function App() {
const [todoList, setTodoList] = useState([]);
useEffect(() => {
async function getTodo() {
const response = await axios.get('http://localhost/laravel/public/api/todo');
setTodoList(response.data);
 }
getTodo();
}, []);
return (
<div>
{todoList.map((todo) =>
<p> {todo.name} </p>
)}
</div>
);
}
export default App;
Your todoList variable is an array of todoLists, e.g. todoList[]. You're trying to read .name of an array, which isn't defined.
You probably want to display a list of items:
return <div className="App">
{todoList.map(todo => <div key={todo.name}>
{todo.name}
</div>)}
</div>;
Your typing otherwise seems fine. One suggestion for readability that I have is simplifying your useState statement:
const [todoList, setTodoList] = useState<todoList>(defaultProps);
With how React declared the type of useState, you can use useState<T> and it'll automatically know that it's returning a [T, (value: T) => void].
Another small note: Usually interfaces/types are PascalCase, e.g. TodoList, to make sure it doesn't clash with variables and function parameters which usually have camelCase, e.g. your todoList variable.

React event.target setState. Set list item backgroundColor

After clicking on the item list I want to change its background color. After clicking on another, I want the color to return to the default. I did something like that:
import React, {useState} from 'react'
function Node({expanded, name}) {
const [targetS, setTargetS] = useState()
const Select = (element) => {
const {target} = element
targetS && targetS.backgroundColor = ''
setTargetS(target)
targetS.style.backgroundColor = 'orange'
}
return (
<li onClick={Select}>
{expanded? '-':'+'} {name}
</li>
)
}
export default Node
but it doesn't work as I think
If you're using React, take advantage of writing JavaScript inside the JSX and React state. You don't need to manipulate the color of your element using event object directly. (The way you are doing it needs some correction also). You can let React be responsible for triggering the color change by leveraging react state to act as a toggle for your li className.
Create a activeNode state and its setter setActiveNode in parent component of Node. Then pass it as follows:-
<Node name={name} expanded={expanded} activeNode={activeNode} setActiveNode={setActiveNode}/>
import React, {useState} from 'react'
function Node({expanded, name, setActiveNode, activeNode}) {
const selectElement = (name) => {
setActiveNode(name)
}
return (
<li className={activeNode===name?"orange":""} onClick={()=>selectElement(name)}>
{expanded? '-':'+'} {name}
</li>
)
}
export default Node
Inside your stylesheet:-
orange{
background:"orange"
}

useContext is giving undefined

I'm trying to pass value from my parent component for making some API call. I'm using context to pass the value between two components but I'm getting undefined in the console log. Could you guys please help me.
Parent component.
import Travel from './Travel'
export const TransactionAccountIdContext = createContext();
export default function Accounts() {
const [accountId, setAccountId] = useState(0);
const setTransactionAccountId = e => {
console.log("Clicked ID", e.currentTarget.value);
setAccountId(e.currentTarget.value);
};
return (
<div className={classes.root}>
<Button
variant="contained"
value={account.id}
onClick={setTransactionAccountId}
className={classes.button}
startIcon={<ReceiptIcon />}
>
Show Transactions
</Button>
<TransactionAccountIdContext.Provider value={"1212121"}>
<Travel />
</TransactionAccountIdContext.Provider>
</div>
);
}
child component (Travel.jsx)
import TransactionAccountIdContext from "./accounts";
export default function MaterialTableDemo() {
const accountId = useContext(TransactionAccountIdContext);
console.log("accountId", accountId);
return <h1>{accountId}</h1>;
}
I'm also making some API calls using react hooks in parent and child components but I have removed it here to reduce the size of the question. Could anyone of you please tell us what can be the issue.
I believe this is due to your import syntax in Travel.jsx.
Your TransactionAccountIdContext is being exported from the parent as a named constant. It needs to be destructured from the import in the child component.
eg:
/// Travel.jsx
import { TransactionAccountIdContext } from "./accounts";

ReactJS hooks useContext issue

I'm kind of to ReactJS and I'm trying to use useContext with hooks but I'm having some trouble. I've been reading through several articles but I could not understand it.
I understand its purpose, but I can't figure out how to make it work properly. If I'm correct, the purpose is to be able to avoid passing props down to every children and be able to access values from a common provider at any depth of the component tree. This includes functions and state values. Please correct me if I'm wrong.
I've been testing with the following files. This is the ManagerContext.js file:
import { createContext } from 'react';
const fn = (t) => {
console.log(t);
}
const ctx = createContext({
title: 'This is a title',
editing: false,
fn: fn,
})
let ManagerContext = ctx;
export default ManagerContext;
Then I have the LessonManager.js file which is used in my main application:
import React from 'react';
import LessonMenu from './LessonMenu.js';
export default function LessonManager() {
return (
<LessonMenu />
)
}
And finally the LessonMenu.js:
import React from 'react';
import 'rsuite/dist/styles/rsuite.min.css';
import ManagerContext from './ManagerContext.js';
export default function LessonMenu() {
const value = React.useContext(ManagerContext);
return (
<div>
<span>{value.title}</span>
<button
onClick={()=>value.fn('ciao')}
>click</button>
<button
onClick={()=>value.title = 'new title'}
>click</button>
</div>
)
}
In the LessonMenu.js file the onClick={()=>value.fn('ciao')} works but the onClick={()=>value.title = 'new title'} doesn't re render the component.
I know something is wrong, but can someone make it a bit clearer for me?
In order for rerendering to occur, some component somewhere must call setState. Your code doesn't do that, so no rendering happens.
The setup you've done for the ManagerContext creates a default value, but that's only going to get used if you don't render any ManagerContext.Provider in your component tree. That's what you're doing now, but it's almost certainly not what you want to. You'll want to have some component near the top of your tree render a ManagerContext.Provider. This component can will be where the state lives, and among the data it sends down will be a function or functions which set state, thus triggering rerendering:
export default function LessonManager() {
const [title, setTitle] = useState('SomeOtherTitle');
const [editing, setEditing] = useState(false);
const value = useMemo(() => {
return {
title,
setTitle,
editing,
setEditing,
log: (t) => console.log(t)
}
}, [title, editing]);
return (
<ManagerContext.Provider value={value} >
<LessonMenu />
</ManagerContext.Provider/>
)
}
// used like:
export default function LessonMenu() {
const value = React.useContext(ManagerContext);
return (
<div>
<span>{value.title}</span>
<button onClick={() => value.log('ciao')}>
click
</button>
<button onClick={() => value.setTitle('new title')}>
click
</button>
</div>
)
}

Resources