اذهب إلى المحتوى

أحمد حبنكة

الأعضاء
  • المساهمات

    338
  • تاريخ الانضمام

  • تاريخ آخر زيارة

كل منشورات العضو أحمد حبنكة

  1. لننظر إلى السطر التالي: setClock(clock + 1); من أين تأتي clock؟ من خارج التابع الممرر إلى useEffect وبالتالي لدينا closure وقيمة الـclock عند استدعاء التابع داخل useEffect هي 0 لذا التعليمة السابقة مكافئة للتالية: setClock(0 + 1); // => setClock(1) هذا يحصل كل ثانية ولكن لا معنى لذلك ﻷنك تضع قيمة ثابتة. لحل المشكلة نستخدم نسخة setClock التي تمرر لها تابعاً هكذا: setClock(clock => clock + 1); بهذه الطريقة تحل المشكلة بإذن الله. طبعاً هناك طريقة ثانية وهي تمرير clock ضمن dependencies array ولكن تلك الطريقة ستقوم بعمل clearInterval ثم setInterval بشكل متكرر مما يؤذي اﻷداء لذلك لم نتبعها.
  2. أولاً لماذا تريد اﻻستيراد بشكل ديناميكي؟ هل لتختار بين عدة components أيها يجب أن تضع؟ حينها استعمل ؟: هكذا: import React from 'react'; import Page1 from './page1' import Page2 from './page2' export default function App() { return ( <div> <h1>react app</h1> {someCondition ? <Page1 /> : <Page2 />} </div> ); } اﻻستيراد الديناميكي يستخدم فقط حين تريد تطبيق ما يسمى code splitting وهي تقنية لتسريع اﻷداء هدفها فصل جزء من الكود لتحميله فقط عند الحاجة إليه بدلاً من تحميله دائماً بغض النظر عن استخدام الصفحة الحالية له. إن كان هدفك هو code splitting فأنا أنصح باستخدام مكتبة loadable-components الموجودة في هذا الرابط : https://loadable-components.com/ باستخدام مكتبة loadable-components نكتب اﻵتي: import React, { Suspense } from 'react'; import loadable from '@loadable/component' const OtherComponent = loadable(() => import('./OtherComponent'), { fallback: <div>Loading...</div>, }); function MyComponent() { return ( <div> <OtherComponent /> </div> ); } لاحظ أننا نستخدم import كتابع اﻵن، حين استعمالها كتابع يرد هذا التابع Promise حين انتهائه يرد webpack module وطريقة الفصل هذه مبرمجة ضمن webpack نفسه، كل ما تفعله loadable-components هو تسهيل التعامل مع dynamic import فقط لا غير فمن اﻷشياء التي تؤمنها مثلاً معامل fallback الممرر أعلاه، ما هذا المعامل؟ كما قلت هدف code splitting هو فصل جزء من الكود وتحميله فقط عند الحاجة، عندما تبدأ MyComponent بـrender فقط حينها يتم تحميل كود OtherComponent ، ريثما ينتهي التحميل ماذا تعرض للمستخدم؟ تعرض له ما تمرره للـfallback ، عند انتهاء تحميل كود OtherComponent يتم إخفاء fallback واستبداله بـOtherComponent نفسها. ملاحظة أخيرة: الـcode splitting مفيد للأداء فقط إن كنت متأكداً أن OtherComponent تستعمل فقط من قبل صفحات معينة أما إن كانت معظم الصفحات تستعملها فلا معنى من استخدام dynamic import.
  3. إن مكتبة axios حين تمرر لها body فإنها تفترض أنك تريد أن تعمل POST لـJSON وهذا ما ترسله للمخدم، إذا أردت إرسال multipart/form-data يجب عليك إنشاء FormData object وملؤه بالحقول هكذا: // تعريف متغير ليستقبل formData const payload = new FormData(); // إعطائه القيم payload.append('userName', 'usertest'); payload.append('userEmail', 'usertest@gmail.com'); payload.append('file',fileObject) // if you have <input type="file"/> you can get fileObject from inputElement.files[0] if input is not multiple or inputElement.files if it is multiple axios({ method: 'post', url: '/addUser', data: payload }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); لاحظ أننا أزلنا Content-Type header ولا داعي له بل من الخطأ تمريره ﻷن axios عند تمرير FormData فإنها تفهم أن Content-Type يجب أن يكون multipart. طبعاً أنت تعلم أن multipart يستخدم فقط إن كان هناك file upload أما إذا كانت جميع حقولك عادية حينها لا نمرر FormData object بل نمرر URLSearchParams object بالشكل التالي: axios({ method: 'post', url: '/addUser', data: new URLSearchParams(body) // body is a regular javascript object }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); حينها تمرر axios الـContent-Type header بقيمة application/x-www-form-urlencoded أخيراً إن كنت تريد تمرير JSON للسيرفر حينها تقوم باﻵتي: axios({ method: 'post', url: '/addUser', data: body // body is a regular javascript object }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); }); حينها يكون Content-Type يساوي application/json
  4. إن useEffect تدمج الـlifecycle methods الثلاثة في تابع واحد، useEffect تستعمل حين تريد تنفيذ كود معين عند كل تغير لمتحولات معينة، فمثلاً الكود التالي: useEffect(() => { console.log(name); },[name]) سيطبع name كلما تغير، قد يكون name هذا prop من أب وقد يكون state ، لا يهم كيف يتغير كل ما يهم أنه كلما تغير سنقوم بطباعته، طبعاً الكود بداخل useEffect ينفذ مرة واحدة على اﻷقل ولذا يمكن استعماله بديلاً عن componentDidMount هكذا: useEffect(() => { // do something },[]); لاحظ المصفوفة الفارغة، تلك طريقة نخبر فيها useEffect أن الكود لا يعتمد على أية متحولات لذا ينفذ مرة واحدة عند كل mount للـcomponent. طبعاً يمكننا تمرير عدة متحولات داخل المصفوفة مثل اﻵتي: useEffect(() => { console.log(a+b); },[a,b]); الكود السابق يطبع مجموع a وb كلما تغير a أو تغير b.أخيراً يمكن للتابع الممرر كـcallback للـuseEffect أن يرد ما يسمى cleanup function ، كما في المثال التالي: useEffect(() => { if(name === 'ahmad'){ window.addEventListener('mousemove',mousemovelistener); return () => { window.removeEventListener('mousemove',mousemovelistener); } } },[name]); الكود السابق يفحص name إن كان يساوي ahmad يضيف listener للحدث mousemove ، عندما يتغير name إلى قيمة مثل "a" نريد للـmousemovelistener أن يزال لذلك كتبنا الكود التالي: return () => { window.removeEventListener('mousemove',mousemovelistener); } عندما ترد تابعاً هكذا يفهم useEffect أن عليه تنفيذ هذا التابع أولاً ثم نغير dependency (والتي في المثال السابق هي name) ثم ننفذ الكود داخل useEffect من جديد. أعتقد أنك قد لاحظت أن useEffect أفضل وأقوى من lifecycle methods ، ليس ذلك فقط بل يمكنك كتابة عدة useEffect في component هكذا: useEffect(() => { console.log(name); },[name]); useEffect(() => { console.log(a+b); },[a,b]); كل effect في المثال السابق مستقل تماماً عن غيره، أليس هذا رائعاً؟!!!
  5. لا يجوز التعديل على this.state بشكل مباشر وإنما فقط من خلال setState، يمكن تحقيق ما تريد بعدة طرق. اﻷولى باستخدام concat: this.setState({ array: this.state.array.concat('new Item') }); الثانية باستخدام rest array: this.setState({ array: [...this.state.array,'new Item'] }); الثالثة نسخ المصفوفة قبل تعديلها هكذا: // make a copy, newArray !== this.state.array const newArray = [...this.state.array] newArray.push('new Item'); this.setState({ array: newArray }); شخصياً في حالتك أفضل rest array لكن الطريقة الثالثة قد تكون ضرورية في حال كان التعديل على المصفوفة أعقد من مجرد إضافة عنصر إليها.
  6. إن استدعاء Child.getAlert هو في الحقيقة محاولة استدعاء تابع static على الصف Child ولكن getAlert هو instance method وليس static method. حتى تستدعي instance method تحتاج إلى reference للـinstance التي يبنيها react والتي تتحقق باستخدام ما يسمى بـref بالشكل اﻵتي: class Parent extends Component { constructor(){ this.childRef = React.createRef(); this.findChildAlert = this.findChildAlert.bind(this); } fireChildAlert() { // التحقق من وجود مرجع للمكون Child // ومن ثم استدعاء الدالة بداخله this.childRef.current && this.childRef.current.getAlert(); } render() { return ( // ربط مرجع المكون الداخلي بالكون Parent <Child ref={this.childRef}> // تنفيذ الدالة عند الضغط <button onClick={() => this.fireChildAlert()}>Click</button> </Child> ); } } class Child extends Component { getAlert() { alert('clicked'); } render() { return ( <h1 >Child component</h1> ); } } مع ذلك لماذا تريد استدعاء تابع من اﻻبن بهذا الشكل؟ ألا تستطيع تحقيق الميزة التي تريدها من دون ذلك؟ شخصياً لا أفضل استعمال ref بهذه الطريقة ولو تخبرنا بهدفك الحقيقي من استدعاء getAlert لربما نعطيك طريقة أفضل من refs. بالمناسبة الـref ليس فقط من أجل Components بل هو يعمل على html elements أيضاً وحينها يعطيك الـReactJS مؤشراً على DOM Element ، مثال: class A extends React.Component{ constructor(){ this.inputRef = React.createRef(); this.handleClick = this.handleClick.bind(this); } handleClick(){ // inputRef.current is HTMLInputElement this.inputRef.current && this.inputRef.current.focus(); } render(){ return ( <div> <input type="text" ref={this.inputRef} /> <button onClick={this.handleClick()}>Click to Focus on input </button> </div> ); } } يمكن قراءة المزيد في هذا الرابط: https://reactjs.org/docs/refs-and-the-dom.html
  7. أراك تستعمل React.createClass فلماذا؟ هذا التابع قديم جداً وموجود فقط لدعم ES5 التي عفا عليها الزمان من وقت طويل. بالنسبة لما تريد فعله فيجب استعمال ref وليس document.getElementById وذلك ﻷن document.getElementById يجلب عنصر html بينما ما تريده أنت هو reference على ProgressBar component ﻷنك تريد استدعاء addPercent method منها. يمكن تحقيق ما تريد بالكود التالي: class ProgressBar extends React.Component { constructor() { this.state = { finished: this.props.finished }; }, addPrecent(value) { this.setState({ finished: this.state.finished + value }); }, render() { let finished = this.state.finished; if (finished < 0) { finished = 0 }; // هنا يتم عمل مكون Progress bar ولم أقم بإرفاق الكود لعدم أهميته في المشكلة return (...); } // المكون الرئيسي / الأب class App extends React.Component { constructor(){ this.progressBarRef = React.createRef(); this.handleClick = this.handleClick.bind(this); } handleClick(){ this.progressBarRef.addPrecent(10); }, render() { return ( <div class="center"> <ProgressBar ref={this.progressBarRef} finished={25} id="Progress" /> <input type="button" onClick={this.handleClick} value="+10" /> </div> ) } }); باستعمال ref نضمن وصولنا إلى component instance وفي حال استعملناها على عنصر html عادي فإننا نضمن وصولنا إلى html element لنقوم بعمل focus عليه مثلاً وإلخ ولكن انتبه أن this.progressBarRef سيكون undefined حتى يتم عمل render للـProgressbar أو عنصر html أو أياً كان الذي وضعت ref عليه. طبعاً لاحظت أنني ألغيت التعديل على props، لا يجوز بتاتاً التعديل على props الممرر من قبل اﻷب أبداً وإنما تضعها ضمن state وتعدل عليها أو تدع اﻷب يعدل عليها. طبعاً يمكن تحقيق ما تريده بشكل أسهل من دون ref هكذا: class ProgressBar extends React.Component { render(){ let finished = this.props.finished; if (finished < 0) { finished = 0 }; // هنا يتم عمل مكون Progress bar ولم أقم بإرفاق الكود لعدم أهميته في المشكلة return (...); } // المكون الرئيسي / الأب class App extends React.Component { constructor(){ this.handleClick = this.handleClick.bind(this); this.state = { finished: 25 } } handleClick() { this.setState({finished: this.state.finished + 10}) }, render() { return ( <div class="center"> <ProgressBar finished={this.state.finished} /> <input type="button" onClick={this.handleClick} value="+10" /> </div> ) } }); إذاً استعمال document.getElementById خاطئ في React ؟ لا ليس خاطئاً ولكنه لا ينطبق على حالتك هذا كل ما في اﻷمر. أرجو منك ألا تستعمل createClass من جديد ﻷن الزمان عفا عليه منذ زمن طويل.
  8. هل يمكنك مشاركة مجلد المشروع كملف zip ؟
  9. الطريقة الوحيدة لفعل ما تريد هي تعريف متحول وإسناد عنصر JSX المطلوب إليه حسب قيمة props هكذا: import React from 'react' export default function Dynamic(props) { let H = `h${props.head}`; return ( <div> <H>{content}</H> </div> ) } يمكنك تسمية المتحول H بأي شيء شرط أن يبدأ بحرف كبير، أكرر حرفاً كبيراً ﻷنه لن يعمل بدون ذلك. قد تسأل "ومتى كنا نستطيع استخدام string variable كما لو كان component" ؟!!!! هذه من مقدرات الـReact المخبأة أي أنها غير موجودة في docs ، أنا بصراحة جلبتها من جواب على هذا السؤال: https://stackoverflow.com/questions/33471880/dynamic-tag-name-in-jsx-and-react لا أدري كيف علم صاحب الجواب بوجود هكذا طريقة ولكنها طريقة فعالة وجميلة وليس فقط أنك استطعت اﻻختيار بين وسوم العناوين بل يمكنك تمرير أي html attributes تدعمها العناوين h1,2,3 إلخ ويمكنك تمرير onClick أيضاً وكل شيء تريده. بالطبع إن احتجت في المستقبل أن تختار بين عدة Components ديناميكياً بدلاً من اﻻختيار بين عدة وسوم يمكن إسناد تابع component إلى متحول يبدأ بحرف كبير، مثال للتوضيح: import React from "react"; function A(){ return (<h1>2</h1>); } function B(){ return (<p>hello</p>); } const components = { component1: A, component2: B } function C(props){ const CustomComponent = components[`component${props.number}`]; return <CustomComponent /> } المهم ألا تنسى قاعدة البدء بحرف كبير ﻷن React يترجم أي شيء لا يبدأ بحرف كبير إلى وسم html ونحن لا نريد ذلك في الحالات أعلاه.
  10. هناك خطآن في كودك، اﻷول أنك لا تسند أي قيمة لخاصية value للـinput أي يجب أن تكون هكذا: <input onChange={handleChange} type="text" name="username" value={state.username} /> <input onChange={handleChange} type="email" name="email" value={state.email} /> <input onChange={handleChange} type="password" name="password" value={state.password} /> <input onChange={handleChange} type="password" name="confirm_password" value={state.confirm_password} /> في حالتك من دون value تصير input ما يسمى بـuncontrolled وحينها لا يمكنك أن تعدل قيمتها برمجياً من قبل React بدون استعمال ref والذي لا يفضل استعمالها في حالتك بل يفضل تعيين قيمة value وبهذا يمكنك تغيير قيمة input بـsetState بسيطة. الثاني في هذا الكود: const handleChange = (e) => { setState((prev) => ({ ...prev, [e.target.name]: e.target.vale })); }; اسمها e.target.value وليس e.target.vale نغيرها إلى هذا: const handleChange = (e) => { setState((prev) => ({ ...prev, [e.target.name]: e.target.value })); }; ملاحظة أخيرة: يفضل تسمية component بـSignUp بالحرف الكبير وليس signup فهذا هو العرف الشائع في مجتمع Reactjs
  11. سبب الخطأ هو أنك تقوم بـexport default لذا يتم عمل import بالطريقة التالية: import rootReducer from '../../store/reducers'; لقد سميته rootReducer وليس combineReducers ﻷن rootReducer هو نتيجة استدعاء التابع combineReducers وليس التابع نفسه كما أن combineReducers يجب أن يأتي من redux. بشكل عام أي export default يتم عمل import بالطريقة أعلاه أما export عادية فيتم عمل import لها بنفس طريقتك السابقة، إليك مثالاً يوضح اﻷمر: // somefile.js export function add(a,b){return a+b;} export function sub(a,b){return a-b;} export default function mul(a,b){return a * b;} // someOtherfile.js import mul,{add,sub} from "somefile.js"; mul(2,3) // 6 add(2,3) // 5 sub(2,3) // -1
  12. إن useEffect تدمج الـlifecycle methods الثلاثة في تابع واحد، useEffect تستعمل حين تريد تنفيذ كود معين عند كل تغير لمتحولات معينة، فمثلاً الكود التالي: useEffect(() => { console.log(name); },[name]) سيطبع name كلما تغير، قد يكون name هذا prop من أب وقد يكون state ، لا يهم كيف يتغير كل ما يهم أنه كلما تغير سنقوم بطباعته، طبعاً الكود بداخل useEffect ينفذ مرة واحدة على اﻷقل ولذا يمكن استعماله بديلاً عن componentDidMount هكذا: useEffect(() => { // do something },[]); لاحظ المصفوفة الفارغة، تلك طريقة نخبر فيها useEffect أن الكود لا يعتمد على أية متحولات لذا ينفذ مرة واحدة عند كل mount للـcomponent. طبعاً يمكننا تمرير عدة متحولات داخل المصفوفة مثل اﻵتي: useEffect(() => { console.log(a+b); },[a,b]); الكود السابق يطبع مجموع a وb كلما تغير a أو تغير b. أخيراً يمكن للتابع الممرر كـcallback للـuseEffect أن يرد ما يسمى cleanup function ، كما في المثال التالي: useEffect(() => { if(name === 'ahmad'){ window.addEventListener('mousemove',mousemovelistener); return () => { window.removeEventListener('mousemove',mousemovelistener); } } },[name]); الكود السابق يفحص name إن كان يساوي أحمد يضيف listener للحدث mousemove ، عندما يتغير name إلى قيمة مثل "a" نريد للـmousemovelistener أن يزال لذلك كتبنا الكود التالي: return () => { window.removeEventListener('mousemove',mousemovelistener); } عندما ترد تابعاً هكذا يفهم useEffect أن عليه تنفيذ هذا التابع أولاً ثم نغير dependency (والتي في المثال السابق هي name) ثم ننفذ الكود داخل useEffect من جديد. أعتقد أنك قد لاحظت أن useEffect أفضل وأقوى من lifecycle methods ، ليس ذلك فقط بل يمكنك كتابة عدة useEffect في component هكذا: useEffect(() => { console.log(name); },[name]); useEffect(() => { console.log(a+b); },[a,b]); كل effect في المثال السابق مستقل تماماً عن غيره، أليس هذا رائعاً أم ماذا؟!!!
  13. هنالك عدة أخطاء في كودك، اﻷولى أن هذا الكود: useEffect(() => { let mounted = true; if (mounted) { whichFamousFramwork(); } return () => (mounted = false); }, [lang]); مكافئ تماماً لهذا الكود: useEffect(() => { whichFamousFramwork(); }, [lang]); الثانية أن الـuseEffect وكذلك هذا السطر: const [framework, setFramwoek] = useState(''); لا داعي لهما، يمكن استبدال Parent بهذا الكود: export default function ParentComponent() { const [lang, setLang] = useState(''); let framework; switch (lang) { case 'javascript': framework = 'react'; case 'python': framework = 'django'; case 'php': framework = 'laravel'; default: // eslint-disable-next-line no-unused-expressions framework = 'django'; } return ( <div dir="rtl"> <h1>اختر لغة وسنخبرك بأفضل فرايموورك</h1> <div> <button onClick={() => setLang('javascript')}>javascript</button> <button onClick={() => setLang('python')}>python</button> <button onClick={() => setLang('php')}>php</button> </div> {lang && ( <p> بالنسبة ل <span>{framework}</span>, {lang} هو أفضل فرايموورك </p> )} <Child /> </div> ); } بالنسبة للـChild فإعادة تشغيله عند إعادة تشغيل المكون اﻷب أمر طبيعي ولا يجب تجنبه إلا إذا سبب ذلك مشاكل في performance حينها نلجأ ﻷمثال react.memo. إن كان إعادة تشغيل اﻻبن تسبب خطأً في logic فالمشكلة في اﻻبن وليس في اﻷب، في حالتك بالتحديد المشكلة في استخدام ref بهذه الطريقة ﻷنك تزيده مع كل استدعاء لتابع اﻻبن فمن الطبيعي أن يتغير اﻻبن عند عمل rerender له. المفضل في حالتك استعمال useState إما في اﻷب وتمرر للابن كـprops أو في اﻻبن وحينها يجب أن يكون هناك زر ما لتغيير state بدلاً من تغييره في جسم render حتى لا تتسبب في حلقة لا نهائية. بشكل عام لا يجوز تغيير state أو ref داخل render مباشرةً وإنما في حدث مثل onClick أو غيره ﻷن تغييره في render مباشرةً دائماً يسبب مشاكل مثل مشكلتك.
  14. في حالتك يمكن حل المشكلة كاﻵتي: const InputComponent = function() { const name = "My Name"; return ( <input type="text" disabled={name !== undefined && name !== null} /> ); } بهذا حين يكون للـname قيمة ستكون خاصية disabled تساوي true، قد تقول "لكن المتصفح يقوم بعمل disable للـinput لمجرد وجود الخاصية"، لا تقلق بشأن ذلك ﻷن React لا يضيف الخاصية البوليانية إلا إذا كانت true. أما حين تريد حذف أو تمرير خاصية غير بوليانية يمكن اللجوء للطريقة التالية: const InputComponent = function() { const isNumberInput = true; return ( <input type="text" pattern={isNumberInput ? "[0-9]+" : undefined} /> ); } عند إسناد undefined لخاصية فإنها لا تضاف للـHTML وكأنها لم تمرر
  15. الفرق اﻷول وهذا قائم في جميع نسخ الـReact هو شكل الكود: Class Components تعرف ES6 Class وتستخدم inheritance بينما Function Components تستخدم توابع عادية. قبل نسخة React 16.8 كان هناك فرقان آخران جوهريان: الـFunction component لا تستطيع استخدام state، وقتها لم يكن هناك شيء اسمه useState ﻷنه لم يكن هناك شيء اسمه hooks من اﻷساس. الـClass component تستطيع تعريف توابع Lifecycles مثل componentDidMount وغيرها بينما Function component لم تكن تستطيع ذلك ﻷنه لم يكن هناك useEffect. ولكن مع نسخة React 16.8 وظهور hooks لم يعد هناك أي فرق بين Class components وfunction components سوى في الشكل والطريقة، أنا شخصياً صرت أستعمل function components دائماً ليس ﻷنها أسرع، ليس ﻷنني أستطيع فعل أشياء لا أستطيع فعلها بالـClass components وإنما فقط ﻷنها أبسط وأجمل أو باﻷحرى ﻷنني أحببتها أكثر ويبدو أن الكثيرين من مبرمجي الـReact يشاطرونني الرأي إذ لم يعد هناك مكتبة React تقريباً لا تستعمل hooks. صحيح أن فريق الفيسبوك لم يصرح أنه سيلغي Class component ولكني أعتبرها ملغاة بحكم المجتمع.
  16. في حالتك يجب نسخ state object قبل التعديل هكذا: const handleChange = (e) => { const { name, value } = e.target; setForm((prevForm) => { const newForm = {...prevForm}; newForm.info[name] = value; return newForm; }); }; الكود السابق سيعمل لكن المشكلة الوحيدة أننا نقوم بعمل shallow copy وليس deep copy، مشكلة الـshallow copy أنها لا تضمن immutability ﻷننا في الحالة السابقة نعدل على info بشكل مباشر وهذا سيعدل على state بشكل مباشر وهذا خاطئ وإن عمل الكود، في حالة أردنا deep copy أنا أفضل حينها استخدام مكتبة immer من هذا الرابط ، في حالتك باستعمال immer: const handleChange = (e) => { const { name, value } = e.target; setForm((prevForm) => { return produce(prevForm,(draftForm) => { draftForm.info[name] = value; }); }); }; لاحظ أن الكود السابق أسهل بكثير فيم لو قمنا بعمل deep copy بأيدينا حيث تضمن لك مكتبة immer أن تكون state لديك immutable بشكل كامل ومع ذلك تكتب كود مشابه للـmutable. إذا كان state object أعقد بكثير من حالتك هنا أفضل استعمال مكتبة redux وredux-toolkit أو أي بديل تحت مسمى state management library (مثل Mobx مثلاً) حيث تسمح لك تلك المكتبات بتقسيم state الكبيرة إلى أجزاء صغيرة يعالج كل جزء فيها معالجة مستقلة عن بقية الأجزاء مما يجعل إدارة الـstate object الكبير أسهل ناهيك عن توفير ميزات أخرى مثل تنظيم هيكلية التطبيق بنظام موحد جميل وأشياء أخرى كثيرة.
  17. بما أن توابع redux يجب أن تكون pure أي لا يجوز التعديل على state object يدوياً بل إرجاع object جديد مختلف عن السابق إن أردنا التعديل، وفق هذا المبدأ فإن هذا السطر: arr: state.arr.push([action.newItem]) خاطئ ﻷنه يعدل على المصفوفة بشكل مباشر، الحل هو التالي: arr: [...state.arr,action.newItem] السطر السابق يستعمل ميزة array rest حيث تنتج مصفوفة جديدة فيها كل عناصر state.arr ومضافاً إليها action.newItem، يمكن استخدام ميزة array rest لدمج مصفوفتين أيضاً بالشكل اﻵتي: arr: [...state.arr,...action.newItems] ويمكن إضافة عنصر في بداية المصفوفة بدلاً من نهايتها هكذا: arr: [action.newItem,...state.arr] بالمناسبة أنا أنصحك أن تتعلم redux-toolkit وتستخدمها في جميع مشاريع redux وهذا ما ينصح به فريق مطوري redux، لماذا؟ ﻷن مثالك بعد redux-toolkit يمكن استبداله بالكود التالي: import {createSlice} from "@reduxjs/toolkit"; const slice = createSlice({ name: "items", initialState: [], reducers: { addItem(state,action){ state.arr.push(action.payload); } } }); const {actions,reducer} = slice; const {addItem} = actions; export default reducer; export addItem; // addItem is an action creator so we dispatch it like this dispatch(addItem(newItem)); لاحظ أننا استعملنا state.arr.push وهذا صحيح ﻷن redux-toolkit تستعمل مكتبة اسمها immer التي تعمل بالطريقة التالية: الـstate الممرر في addItem method هو draft State object مختلف عن state object المخزن داخل redux ، كل تعديل على هذا draft object تلتقطه مكتبة immer المستعملة من قبل redux-toolkit، عند اﻻنتهاء من التعديلات ترجع مكتبة immer كائن object جديد مختلف عن state object القديم وفيه التعديلات المطلوبة. يمكنك قراءة المزيد عن redux-toolkit هنا ويمكنك قراءة المزيد عن مكتبة immer وفهمها أكثر هنا
  18. الفرق اﻷساسي هو أن React يستهدف الوب بينما React Native يستهدف تطبيقات الجوال. خرج كود React هو ملفات HTML - CSS - JAVASCRIPT ينفذها متصفح الوب، خرج React Native هو إما apk يتم رفعه إلى غوغل بلاي أو IPA يتم رفعه إلى آبل ستور. الnative components في ReactJS هو div وp وبقية عناصر HTML ، الـnative components في React Native هي View وText وغيرها التي تترجم إلى native UI widgets حسب platform أكان أندرويد أم iphone الهدف من ReactJS هو تسهيل برمجة تطبيقات الوب، الهدف من React Native هو برمجة تطبيقات الجوال بلغة موحدة بدلاً من لغة برمجة مختلفة لكل platform مدعومة - أي بدلاً من Swift/ios وJava/Kotlin/Android - وتملك نفس أداء التطبيقات المبرمجة بطريقة native. عدا هذه اﻻختلافات فنعم هما متشابهان كثيراً من حيث أن كليهما يستخدم لغة الجافاسكريبت وكلاهما لهما نفس الطريقة في الكتابة من Components وProps وstate وإلخ.
  19. هل يمكنك إخبارنا لماذا تريد تمرير props إلى اﻷب؟ إذا كنت تريد تغيير شيء في اﻷب مثلاً تريد تغيير state معينة فسأشرح لك كيفية عمل ذلك بمثال، ليكن الكود التالي: const Parent = () => { const [tasks,setTasks] = useState([]); return ( <ul> {tasks.map(v => ( <Child task={v}/> ))} </ul> ); } const Child = (props) => { const {task} = props; return ( <div> <button type="button">Delete</button> {task.name} </div> ); } في الكود السابق نريد عند الضغط على الزر داخل Child component نريد حذف task ضمن اﻷب فكيف نفعل ذلك ونحن لا نستطيع تمرير props إلى اﻷب؟!!! ببساطة يمرر اﻷب تابع إلى اﻻبن بالشكل التالي: const Parent = () => { const [tasks,setTasks] = useState([]); const onDelete = (task) => { const tasksAfterDelete = ... // implement delete functionality however you like setTasks(tasksAfterDelete); } return ( <ul> {tasks.map(v => ( <Child task={v} onDelete={onDelete}/> ))} </ul> ); } const Child = (props) => { const {task,onDelete} = props; return ( <div> <button type="button" onClick={() => onDelete(task)}>Delete</button> {task.name} </div> ); } لاحظ أننا مررنا تابع onDelete من اﻷب إلى اﻻبن واستدعيناه في اﻻبن، هذا الكود هو pattern شائع جداً في React حيث يستقبل اﻻب تابعاً ينفذه عند وقوع حدثٍ ما واﻷب هو من يقرر ماذا سيحصل عند وقوع هذا الحدث. اﻻبن لا يهمه ماذا يفعل اﻷب عند وقوع هذا الحدث، قد يقوم اﻷب مثلاً بطلب Ajax ثم يحدّث state بالـresponse لهذا الطلب مثلاً.
  20. لننظر إلى كود CSS بتمعن، أنت تضع background-color على العنصر ذو الصف .about-me، فلنبحث عن about-me ضمن ملف html. ستجد أنه لا يوجد about-me لكن إن بحثنا عن "about me" سوف نجدها، بالمختصر اسم الصف هو about-me مع dash وليس مسافة إذاً نغير الكود التالي: <div class="about me"> <div class="container"> <div class="image"> <img src="../image/300px.png" alt="test"> </div> <div class="info"> info test </div> </div> </div> إلى التالي: <!-- this is the line that has changed --> <div class="about-me"> <div class="container"> <div class="image"> <img src="../image/300px.png" alt="test"> </div> <div class="info"> info test </div> </div> </div> للعلم لا يمكن لصف CSS أن يكون في اسمه مسافة أصلاً ﻷن الكود التالي: <div class="about me"> يسند صفين مستقلين إلى العنصر واسمهما about و me
  21. هناك عدة أسباب لحصول ذلك ومعظمها لا علاقة لها بترتيب اﻷسطر سواءٌ كانت في اﻷسطر اﻷخيرة أم لا. إن أخبرتنا أكثر عن حالتك يمكنني أن أعطيك السبب لمشكلتك، ما هو كود الـCSS الذي لا يعمل؟ ما هو كود HTML المستهدف؟ ما الذي تريد القيام به؟ تلوين أزرارٍ مثلاً؟
  22. السلام عليكم ورحمة الله وبركاته المشكلة هي أن الـmethod المسمى information في الصف car يأخذ ثلاث معاملات بينما أنت تمررين لا شيء له بهذا بالطبع سيرفض الكومبايلر هذا الكود. لحل المشكلة عليك تعريف نسخة ثانية من تابع information ليصير الصف car هكذا: class car { int ID; string Color; string Model; public void information(int ID,string Color,string Model) { ID = ID; Color = Color; Model = Model; } public void information() { // do something here } public void showd() { Console.WriteLine("this is ID:{0}\n this is color:{1}\nthis is model:{2}", ID, Model, Color); } } ما تضعه داخل النسخة الثانية يتوقف على ما تريد فعله، يمكنك مثلاً فعل اﻵتي: public void information(int ID,string Color,string Model) { ID = ID; Color = Color; Model = Model; } public void information() { information(95," blue", "once"); } أو أي شيء تريده. بالمناسبة هناك خطأ في implementation الخاصة بالتابع information ذو الثلاث معاملات وهي في السطر التالي: ID = ID; ربما تظن أن التعليمة السابقة تسند ID parameter إلى ID Field الموجود ضمن الصف ولكن هذا غير صحيح بل التعليمة السابقة تسند ID parameter إلى نفسه مما يجعلها عديمة الفائدة، الصحيح هو التالي: this.ID = ID; وكذلك اﻷمر بالنسبة للـmodel وcolor، بهذا يصير صف car النهائي هو التالي: class car { int ID; string Color; string Model; public void information(int ID,string Color,string Model) { this.ID = ID; this.Color = Color; this.Model = Model; } public void information() { information(95,"blue","once"); } public void showd() { Console.WriteLine("this is ID:{0}\n this is color:{1}\nthis is model:{2}", ID, Model, Color); } } أرجو أن تكون الفكرة قد أصبحت واضحة بالتوفيق وشكراً لك
  23. وعليكم السلام ورحمة الله وبركاته أولاً نعم يمكن استبدال connect بـuseSelector، كلاهما طريقتان لجلب state من redux إلى component الحالية. من ناحية الوظيفة لا يوجد فرق بينهما. الفرق الوحيد هو أن useSelector تستخدم React Hooks وهي طريقة جديدة لتعريف state ضمن function components أما connect فيستعمل ما يسمى HoC أي Higher Order Component وهي حين يكون لدينا تابع يأخذ component class or function كمعامل ويرد component class آخر. إذاً ماذا نستخدم طالما أنهما يؤديان نفس الوظيفة؟ اﻷمر يعتمد على ذوقك، شخصياً أجد useSelector أجمل وأسهل للفهم وتوفر علي بعض boilerplate، ربما يجد آخرون connect أفضل أو ﻷنهم اعتادوا عليها. أما بالنسبة لما هو شائع فاستخدام Hooks أصبح شائعاً جداً هذه اﻷيام وبالغالب useSelector معه إلا في التطبيقات التي ما زالت تعمل بنسخة React أقل من 16.8 والله أعلم. بالتوفيق وشكراً لك
  24. ما هي قاعدة البيانات التي تستعملها ؟ وهل نحن نتكلم عن تطبيق وب أم عن تطبيق جوال؟ على أية حال مشكلتك مشكلة encoding والحل هو اعتماد utf-8 encoding في التخزين في قاعدة البيانات وكذلك في اﻹظهار. إذا أجبتنا عن اﻷسئلة أعلاه سنتمكن من مساعدتك بشكل أفضل ﻷن text encoding/decoding له خوارزمية واحدة ولكن الكود يختلف باختلاف لغات البرمجة وقواعد البيانات
  25. السلام عليكم ورحمة الله وبركاته سوق العمل بشكل عام الشائع فيه هو php أكثر بكثير من البايثون، البايثون شائعة أكثر في مجال الذكاء الصنعي. هذا إن كان سوق العمل هو ما يهمك لكن إن كنت شخصاً يتعلم البرمجة ﻷول مرة فقد سمعت أن البايثون لغة جيدة كأول لغة يتعلمها الشخص، صحيح أنك لن تعمل بها على اﻷغلب لكن المبادئ التي ستتعلمها فيها تستطيع أن تطبقها في php وC# وغير ذلك من اللغات. أخيراً أقول لك أن هناك مواقع وب مبنية بالبايثون مثل quora ، كل ما هنالك أن البايثون ليست خياراً شائعاً لبرمجة الوب.
×
×
  • أضف...